import of Pyrex 0.9.6.2
authorStefan Behnel <scoder@users.berlios.de>
Thu, 11 Oct 2007 06:08:56 +0000 (08:08 +0200)
committerStefan Behnel <scoder@users.berlios.de>
Thu, 11 Oct 2007 06:08:56 +0000 (08:08 +0200)
19 files changed:
Cython/Compiler/Code.py
Cython/Compiler/Errors.py
Cython/Compiler/ExprNodes.py
Cython/Compiler/Main.py
Cython/Compiler/ModuleNode.py
Cython/Compiler/Naming.py
Cython/Compiler/Nodes.py
Cython/Compiler/Parsing.py
Cython/Compiler/PyrexTypes.py
Cython/Compiler/Scanning.py
Cython/Compiler/Symtab.py
Cython/Compiler/TypeSlots.py
Cython/Compiler/Version.py
Cython/Debugging.py
Cython/Distutils/__init__.py
Cython/Distutils/build_ext.py
Cython/Mac/DarwinSystem.py
Cython/Unix/LinuxSystem.py
Cython/Utils.py

index 5158e3bc11b281781267bcf03f1e7d04af3eda1d..457f5f568b7ed92c5cc99cce9045d65f118b6749 100644 (file)
@@ -19,6 +19,7 @@ class CCodeWriter:
     # in_try_finally   boolean         inside try of try...finally
     # filename_table   {string : int}  for finding filename table indexes
     # filename_list    [string]        filenames in filename table order
+    # exc_vars         (string * 3)    exception variables for reraise, or None
     
     in_try_finally = 0
     
@@ -32,6 +33,7 @@ class CCodeWriter:
         self.error_label = None
         self.filename_table = {}
         self.filename_list = []
+        self.exc_vars = None
     
     def putln(self, code = ""):
         if self.marker and self.bol:
@@ -156,11 +158,13 @@ class CCodeWriter:
     
     def put_var_declaration(self, entry, static = 0, dll_linkage = None,
             definition = True):
-        #print "Code.put_var_declaration:", entry.name, "definition =", definition ###
+        #print "Code.put_var_declaration:", entry.name, repr(entry.type) ###
         visibility = entry.visibility
         if visibility == 'private' and not definition:
+            #print "...private and not definition, skipping" ###
             return
         if not entry.used and visibility == "private":
+            #print "not used and private, skipping" ###
             return
         storage_class = ""
         if visibility == 'extern':
@@ -254,8 +258,6 @@ class CCodeWriter:
     
     def put_init_var_to_py_none(self, entry, template = "%s"):
         code = template % entry.cname
-        #if entry.type.is_extension_type:
-        #      code = "((PyObject*)%s)" % code
         self.put_init_to_py_none(code, entry.type)
 
     def put_pymethoddef(self, entry, term):
@@ -270,6 +272,10 @@ class CCodeWriter:
                 doc_code,
                 term))
     
+    def put_h_guard(self, guard):
+        self.putln("#ifndef %s" % guard)
+        self.putln("#define %s" % guard)
+    
     def error_goto(self, pos):
         lbl = self.error_label
         self.use_label(lbl)
index 0ff98cb5f1d1849eb06b955f28c8311f3efc9714..ed95394db650f5f45ce2ada2bbb6a83d595ed4c4 100644 (file)
@@ -54,14 +54,19 @@ def close_listing_file():
         listing_file.close()
         listing_file = None
 
-def error(position, message):
-    #print "Errors.error:", repr(position), repr(message) ###
-    global num_errors
+def report(position, message):
     err = CompileError(position, message)
     line = "%s\n" % err
     if listing_file:
         listing_file.write(line)
     if echo_file:
         echo_file.write(line)
-    num_errors = num_errors + 1
     return err
+
+def warning(position, message):
+    return report(position, "Warning: %s" % message)
+
+def error(position, message):
+    global num_errors
+    num_errors = num_errors + 1
+    return report(position, message)
index 0456342bbc16a98e1b784983202ef0e6de1481ef..e9475c9ba2ce1480b7e50303d70536dd06284139 100644 (file)
@@ -2,13 +2,14 @@
 #   Pyrex - Parse tree nodes for expressions
 #
 
+import operator
 from string import join
 
 from Errors import error, InternalError
 import Naming
 from Nodes import Node
 import PyrexTypes
-from PyrexTypes import py_object_type, c_long_type, typecast
+from PyrexTypes import py_object_type, c_long_type, typecast, error_type
 import Symtab
 import Options
 
@@ -208,6 +209,14 @@ class ExprNode(Node):
         #  C type of the result_code expression).
         return self.result_ctype or self.type
     
+    def compile_time_value(self, denv):
+        #  Return value of compile-time expression, or report error.
+        error(self.pos, "Invalid compile-time expression")
+    
+    def compile_time_value_error(self, e):
+        error(self.pos, "Error in compile-time expression: %s: %s" % (
+            e.__class__.__name__, e))
+    
     # ------------- Declaration Analysis ----------------
     
     def analyse_target_declaration(self, env):
@@ -486,7 +495,7 @@ class ExprNode(Node):
         if type.is_pyobject or type.is_ptr or type.is_float:
             return CoerceToBooleanNode(self, env)
         else:
-            if not type.is_int:
+            if not type.is_int and not type.is_error:
                 error(self.pos, 
                     "Type '%s' not acceptable as a boolean" % type)
             return self
@@ -548,12 +557,18 @@ class NoneNode(PyConstNode):
     
     value = "Py_None"
     
+    def compile_time_value(self, denv):
+        return None
+    
 
 class EllipsisNode(PyConstNode):
     #  '...' in a subscript list.
     
     value = "Py_Ellipsis"
 
+    def compile_time_value(self, denv):
+        return Ellipsis
+
 
 class ConstNode(AtomicExprNode):
     # Abstract base type for literal constant nodes.
@@ -586,6 +601,9 @@ class NullNode(ConstNode):
 class CharNode(ConstNode):
     type = PyrexTypes.c_char_type
     
+    def compile_time_value(self, denv):
+        return ord(self.value)
+    
     def calculate_result_code(self):
         return "'%s'" % self.value
 
@@ -593,16 +611,25 @@ class CharNode(ConstNode):
 class IntNode(ConstNode):
     type = PyrexTypes.c_long_type
 
+    def compile_time_value(self, denv):
+        return int(self.value)
+    
 
 class FloatNode(ConstNode):
     type = PyrexTypes.c_double_type
 
+    def compile_time_value(self, denv):
+        return float(self.value)
+    
 
 class StringNode(ConstNode):
     #  entry   Symtab.Entry
     
     type = PyrexTypes.c_char_ptr_type
     
+    def compile_time_value(self, denv):
+        return eval('"%s"' % self.value)
+    
     def analyse_types(self, env):
         self.entry = env.add_string_const(self.value)
     
@@ -637,6 +664,9 @@ class LongNode(AtomicExprNode):
     #
     #  value   string
     
+    def compile_time_value(self, denv):
+        return long(self.value)
+    
     def analyse_types(self, env):
         self.type = py_object_type
         self.is_temp = 1
@@ -655,6 +685,9 @@ class ImagNode(AtomicExprNode):
     #
     #  value   float    imaginary part
     
+    def compile_time_value(self, denv):
+        return complex(0.0, self.value)
+    
     def analyse_types(self, env):
         self.type = py_object_type
         self.is_temp = 1
@@ -672,10 +705,34 @@ class NameNode(AtomicExprNode):
     #  Reference to a local or global variable name.
     #
     #  name            string    Python name of the variable
+    #
     #  entry           Entry     Symbol table entry
+    #  interned_cname  string
     
     is_name = 1
     
+    def compile_time_value(self, denv):
+        try:
+            return denv.lookup(self.name)
+        except KeyError:
+            error(self.pos, "Compile-time name '%s' not defined", self.name)
+    
+    def coerce_to(self, dst_type, env):
+        #  If coercing to a generic pyobject and this is a builtin
+        #  C function with a Python equivalent, manufacture a NameNode
+        #  referring to the Python builtin.
+        #print "NameNode.coerce_to:", self.name, dst_type ###
+        if dst_type is py_object_type:
+            entry = self.entry
+            if entry.is_cfunction:
+                var_entry = entry.as_variable
+                if var_entry:
+                    node = NameNode(self.pos, name = self.name)
+                    node.entry = var_entry
+                    node.analyse_rvalue_entry(env)
+                    return node
+        return AtomicExprNode.coerce_to(self, dst_type, env)
+    
     def analyse_as_module(self, env):
         # Try to interpret this as a reference to a cimported module.
         # Returns the module scope, or None.
@@ -689,50 +746,56 @@ class NameNode(AtomicExprNode):
         # Returns the extension type, or None.
         entry = env.lookup(self.name)
         if entry and entry.is_type and entry.type.is_extension_type:
-                return entry.type
-        return None
+            return entry.type
+        else:
+            return None
     
     def analyse_target_declaration(self, env):
         self.entry = env.lookup_here(self.name)
         if not self.entry:
-            #print "NameNode.analyse_target_declaration:", self.name ###
-            #print "...declaring as py_object_type" ###
             self.entry = env.declare_var(self.name, py_object_type, self.pos)
     
     def analyse_types(self, env):
         self.entry = env.lookup(self.name)
         if not self.entry:
             self.entry = env.declare_builtin(self.name, self.pos)
+        self.analyse_rvalue_entry(env)
+        
+    def analyse_target_types(self, env):
         self.analyse_entry(env)
+        if not self.is_lvalue():
+            error(self.pos, "Assignment to non-lvalue '%s'"
+                % self.name)
+            self.type = PyrexTypes.error_type
         
-    def analyse_entry(self, env):
-        self.check_identifier_kind()
+    def analyse_rvalue_entry(self, env):
+        #print "NameNode.analyse_rvalue_entry:", self.name ###
+        #print "Entry:", self.entry.__dict__ ###
+        self.analyse_entry(env)
         entry = self.entry
-        self.type = entry.type
         if entry.is_declared_generic:
             self.result_ctype = py_object_type
-        ## Reference to C array turns into pointer to first element.
-        #while self.type.is_array:
-        #      self.type = self.type.element_ptr_type()
         if entry.is_pyglobal or entry.is_builtin:
-            assert self.type.is_pyobject, "Python global or builtin not a Python object"
             self.is_temp = 1
             if Options.intern_names:
                 env.use_utility_code(get_name_interned_utility_code)
             else:
                 env.use_utility_code(get_name_utility_code)
     
-    def analyse_target_types(self, env):
+    def analyse_entry(self, env):
+        #print "NameNode.analyse_entry:", self.name ###
         self.check_identifier_kind()
-        if self.is_lvalue():
-            self.type = self.entry.type
-        else:
-            error(self.pos, "Assignment to non-lvalue '%s'"
-                % self.name)
-            self.type = PyrexTypes.error_type
-    
+        entry = self.entry
+        type = entry.type
+        self.type = type
+        if entry.is_pyglobal or entry.is_builtin:
+            assert type.is_pyobject, "Python global or builtin not a Python object"
+            if Options.intern_names:
+                self.interned_cname = env.intern(self.name)
+
     def check_identifier_kind(self):
         #print "NameNode.check_identifier_kind:", self.entry.name ###
+        #print self.entry.__dict__ ###
         entry = self.entry
         entry.used = 1
         if not (entry.is_const or entry.is_variable 
@@ -776,8 +839,9 @@ class NameNode(AtomicExprNode):
         return self.entry.cname
     
     def generate_result_code(self, code):
-        if not hasattr(self, 'entry'):
-            error(self.pos, "INTERNAL ERROR: NameNode has no entry attribute during code generation")
+        assert hasattr(self, 'entry')
+        #if not hasattr(self, 'entry'):
+        #      error(self.pos, "INTERNAL ERROR: NameNode has no entry attribute during code generation")
         entry = self.entry
         if entry is None:
             return # There was an error earlier
@@ -792,9 +856,10 @@ class NameNode(AtomicExprNode):
                     '%s = __Pyx_GetName(%s, %s); if (!%s) %s' % (
                     self.result_code,
                     namespace, 
-                    entry.interned_cname,
+                    #entry.interned_cname,
+                    self.interned_cname,
                     self.result_code, 
-                    code.error_goto(self.pos)))                
+                    code.error_goto(self.pos)))
             else:
                 code.putln(
                     '%s = __Pyx_GetName(%s, "%s"); if (!%s) %s' % (
@@ -805,6 +870,7 @@ class NameNode(AtomicExprNode):
                     code.error_goto(self.pos)))                
 
     def generate_assignment_code(self, rhs, code):
+        #print "NameNode.generate_assignment_code:", self.name ###
         entry = self.entry
         if entry is None:
             return # There was an error earlier
@@ -814,7 +880,8 @@ class NameNode(AtomicExprNode):
                 code.putln(
                     'if (PyObject_SetAttr(%s, %s, %s) < 0) %s' % (
                         namespace, 
-                        entry.interned_cname,
+                        #entry.interned_cname,
+                        self.interned_cname,
                         rhs.py_result(), 
                         code.error_goto(self.pos)))
             else:
@@ -962,25 +1029,23 @@ class NextNode(AtomicExprNode):
                 "break;")
         code.putln(
             "}")
-        
+
 
 class ExcValueNode(AtomicExprNode):
     #  Node created during analyse_types phase
     #  of an ExceptClauseNode to fetch the current
     #  exception value.
     
-    def __init__(self, pos, env):
+    def __init__(self, pos, env, var):
         ExprNode.__init__(self, pos)
         self.type = py_object_type
-        self.is_temp = 1
-        env.use_utility_code(get_exception_utility_code)
+        self.var = var
     
+    def calculate_result_code(self):
+        return self.var
+
     def generate_result_code(self, code):
-        code.putln(
-            "%s = __Pyx_GetExcValue(); if (!%s) %s" % (
-                self.result_code,
-                self.result_code,
-                code.error_goto(self.pos)))
+        pass
 
 
 class TempNode(AtomicExprNode):
@@ -1019,6 +1084,14 @@ class IndexNode(ExprNode):
     
     subexprs = ['base', 'index']
     
+    def compile_time_value(self, denv):
+        base = self.base.compile_time_value(denv)
+        index = self.index.compile_time_value(denv)
+        try:
+            return base[index]
+        except Exception, e:
+            self.compile_time_value_error(e)
+    
     def is_ephemeral(self):
         return self.base.is_ephemeral()
     
@@ -1042,7 +1115,7 @@ class IndexNode(ExprNode):
                 self.type = PyrexTypes.error_type
             if self.index.type.is_pyobject:
                 self.index = self.index.coerce_to(
-                    PyrexTypes.c_int_type, env)
+                    PyrexTypes.c_py_ssize_t_type, env)
             if not self.index.type.is_int:
                 error(self.pos,
                     "Invalid index type '%s'" %
@@ -1104,6 +1177,15 @@ class SliceIndexNode(ExprNode):
     
     subexprs = ['base', 'start', 'stop']
     
+    def compile_time_value(self, denv):
+        base = self.base.compile_time_value(denv)
+        start = self.start.compile_time_value(denv)
+        stop = self.stop.compile_time_value(denv)
+        try:
+            return base[start:stop]
+        except Exception, e:
+            self.compile_time_value_error(e)
+    
     def analyse_target_declaration(self, env):
         pass
 
@@ -1114,7 +1196,7 @@ class SliceIndexNode(ExprNode):
         if self.stop:
             self.stop.analyse_types(env)
         self.base = self.base.coerce_to_pyobject(env)
-        c_int = PyrexTypes.c_int_type
+        c_int = PyrexTypes.c_py_ssize_t_type
         if self.start:
             self.start = self.start.coerce_to(c_int, env)
         if self.stop:
@@ -1164,7 +1246,7 @@ class SliceIndexNode(ExprNode):
         if self.stop:
             return self.stop.result_code
         else:
-            return "0x7fffffff"
+            return "PY_SSIZE_T_MAX"
     
     def calculate_result_code(self):
         # self.result_code is not used, but this method must exist
@@ -1178,6 +1260,15 @@ class SliceNode(ExprNode):
     #  stop      ExprNode
     #  step      ExprNode
     
+    def compile_time_value(self, denv):
+        start = self.start.compile_time_value(denv)
+        stop = self.stop.compile_time_value(denv)
+        step = step.step.compile_time_value(denv)
+        try:
+            return slice(start, stop, step)
+        except Exception, e:
+            self.compile_time_value_error(e)
+
     subexprs = ['start', 'stop', 'step']
     
     def analyse_types(self, env):
@@ -1216,6 +1307,14 @@ class SimpleCallNode(ExprNode):
     coerced_self = None
     arg_tuple = None
     
+    def compile_time_value(self, denv):
+        function = self.function.compile_time_value(denv)
+        args = [arg.compile_time_value(denv) for arg in self.args]
+        try:
+            return function(*args)
+        except Exception, e:
+            self.compile_time_value_error(e)
+
     def analyse_types(self, env):
         function = self.function
         function.is_called = 1
@@ -1371,6 +1470,17 @@ class GeneralCallNode(ExprNode):
     
     subexprs = ['function', 'positional_args', 'keyword_args', 'starstar_arg']
 
+    def compile_time_value(self, denv):
+        function = self.function.compile_time_value(denv)
+        positional_args = self.positional_args.compile_time_value(denv)
+        keyword_args = self.keyword_args.compile_time_value(denv)
+        starstar_arg = self.starstar_arg.compile_time_value(denv)
+        try:
+            keyword_args.update(starstar_arg)
+            return function(*positional_args, **keyword_args)
+        except Exception, e:
+            self.compile_time_value_error(e)
+
     def analyse_types(self, env):
         self.function.analyse_types(env)
         self.positional_args.analyse_types(env)
@@ -1426,6 +1536,13 @@ class AsTupleNode(ExprNode):
     
     subexprs = ['arg']
     
+    def compile_time_value(self, denv):
+        arg = self.arg.compile_time_value(denv)
+        try:
+            return tuple(arg)
+        except Exception, e:
+            self.compile_time_value_error(e)
+
     def analyse_types(self, env):
         self.arg.analyse_types(env)
         self.arg = self.arg.coerce_to_pyobject(env)
@@ -1463,6 +1580,18 @@ class AttributeNode(ExprNode):
     entry = None
     is_called = 0
 
+    def compile_time_value(self, denv):
+        attr = self.attribute
+        if attr.beginswith("__") and attr.endswith("__"):
+            self.error("Invalid attribute name '%s' in compile-time expression"
+                % attr)
+            return None
+        obj = self.arg.compile_time_value(denv)
+        try:
+            return getattr(obj, attr)
+        except Exception, e:
+            self.compile_time_value_error(e)
+
     def analyse_target_declaration(self, env):
         pass
     
@@ -1542,7 +1671,7 @@ class AttributeNode(ExprNode):
         if target:
             NameNode.analyse_target_types(self, env)
         else:
-            NameNode.analyse_entry(self, env)
+            NameNode.analyse_rvalue_entry(self, env)
     
     def analyse_as_ordinary_attribute(self, env, target):
         self.obj.analyse_types(env)
@@ -1729,6 +1858,9 @@ class SequenceNode(ExprNode):
     is_sequence_constructor = 1
     unpacked_items = None
     
+    def compile_time_value_list(self, denv):
+        return [arg.compile_time_value(denv) for arg in self.args]
+
     def analyse_target_declaration(self, env):
         for arg in self.args:
             arg.analyse_target_declaration(env)
@@ -1809,6 +1941,13 @@ class SequenceNode(ExprNode):
 class TupleNode(SequenceNode):
     #  Tuple constructor.
 
+    def compile_time_value(self, denv):
+        values = self.compile_time_value_list(denv)
+        try:
+            return tuple(values)
+        except Exception, e:
+            self.compile_time_value_error(e)
+    
     def generate_operation_code(self, code):
         code.putln(
             "%s = PyTuple_New(%s); if (!%s) %s" % (
@@ -1837,6 +1976,9 @@ class TupleNode(SequenceNode):
 class ListNode(SequenceNode):
     #  List constructor.
     
+    def compile_time_value(self, denv):
+        return self.compile_time_value_list(denv)
+
     def generate_operation_code(self, code):
         code.putln("%s = PyList_New(%s); if (!%s) %s" %
             (self.result_code,
@@ -1866,6 +2008,14 @@ class DictNode(ExprNode):
     #
     #  key_value_pairs  [(ExprNode, ExprNode)]
     
+    def compile_time_value(self, denv):
+        pairs = [(key.compile_time_value(denv), value.compile_time_value(denv))
+            for (key, value) in self.key_value_pairs]
+        try:
+            return dict(pairs)
+        except Exception, e:
+            self.compile_time_value_error(e)
+    
     def analyse_types(self, env):
         new_pairs = []
         for key, value in self.key_value_pairs:
@@ -2002,6 +2152,13 @@ class PyCFunctionNode(AtomicExprNode):
 #
 #-------------------------------------------------------------------
 
+compile_time_unary_operators = {
+    'not': operator.not_,
+    '~': operator.inv,
+    '-': operator.neg,
+    '+': operator.pos,
+}
+
 class UnopNode(ExprNode):
     #  operator     string
     #  operand      ExprNode
@@ -2016,6 +2173,18 @@ class UnopNode(ExprNode):
     
     subexprs = ['operand']
     
+    def compile_time_value(self, denv):
+        func = compile_time_unary_operators.get(self.operator)
+        if not func:
+            error(self.pos,
+                "Unary '%s' not supported in compile-time expression"
+                    % self.operator)
+        operand = self.operand.compile_time_value(denv)
+        try:
+            return func(operand)
+        except Exception, e:
+            self.compile_time_value_error(e)
+
     def analyse_types(self, env):
         self.operand.analyse_types(env)
         if self.is_py_operation():
@@ -2063,6 +2232,13 @@ class NotNode(ExprNode):
     #
     #  operand   ExprNode
     
+    def compile_time_value(self, denv):
+        operand = self.operand.compile_time_value(denv)
+        try:
+            return not operand
+        except Exception, e:
+            self.compile_time_value_error(e)
+
     subexprs = ['operand']
     
     def analyse_types(self, env):
@@ -2185,6 +2361,10 @@ class TypecastNode(ExprNode):
     def analyse_types(self, env):
         base_type = self.base_type.analyse(env)
         _, self.type = self.declarator.analyse(base_type, env)
+        if self.type.is_cfunction:
+            error(self.pos,
+                "Cannot cast to a function type")
+            self.type = PyrexTypes.error_type
         self.operand.analyse_types(env)
         to_py = self.type.is_pyobject
         from_py = self.operand.type.is_pyobject
@@ -2277,6 +2457,40 @@ class SizeofVarNode(SizeofNode):
 #
 #-------------------------------------------------------------------
 
+compile_time_binary_operators = {
+    '<': operator.lt,
+    '<=': operator.le,
+    '=': operator.eq,
+    '!=': operator.ne,
+    '>=': operator.ge,
+    '>': operator.gt,
+    'is': operator.is_,
+    'is_not': operator.is_not,
+    '+': operator.add,
+    '&': operator.and_,
+    '/': operator.div,
+    '//': operator.floordiv,
+    '<<': operator.lshift,
+    '%': operator.mod,
+    '*': operator.mul,
+    '|': operator.or_,
+    '**': operator.pow,
+    '>>': operator.rshift,
+    '-': operator.sub,
+    #'/': operator.truediv,
+    '^': operator.xor,
+    'in': lambda x, y: x in y,
+    'not_in': lambda x, y: x not in y,
+}
+
+def get_compile_time_binop(node):
+    func = compile_time_binary_operators.get(node.operator)
+    if not func:
+        error(node.pos,
+            "Binary '%s' not supported in compile-time expression"
+                % self.operator)
+    return func
+
 class BinopNode(ExprNode):
     #  operator     string
     #  operand1     ExprNode
@@ -2292,6 +2506,15 @@ class BinopNode(ExprNode):
     
     subexprs = ['operand1', 'operand2']
     
+    def compile_time_value(self, denv):
+        func = get_compile_time_binop(self)
+        operand1 = self.operand1.compile_time_value(denv)
+        operand2 = self.operand2.compile_time_value(denv)
+        try:
+            return func(operand1, operand2)
+        except Exception, e:
+            self.compile_time_value_error(e)
+
     def analyse_types(self, env):
         self.operand1.analyse_types(env)
         self.operand2.analyse_types(env)
@@ -2350,6 +2573,10 @@ class NumBinopNode(BinopNode):
     def analyse_c_operation(self, env):
         type1 = self.operand1.type
         type2 = self.operand2.type
+        if self.operator == "**" and type1.is_int and type2.is_int:
+            error(self.pos, "** with two C int types is ambiguous")
+            self.type = error_type
+            return
         self.type = self.compute_c_result_type(type1, type2)
         if not self.type:
             self.type_error()
@@ -2361,7 +2588,9 @@ class NumBinopNode(BinopNode):
             return None
     
     def c_types_okay(self, type1, type2):
-        return type1.is_numeric and type2.is_numeric
+        #print "NumBinopNode.c_types_okay:", type1, type2 ###
+        return (type1.is_numeric  or type1.is_enum) \
+            and (type2.is_numeric  or type2.is_enum)
 
     def calculate_result_code(self):
         return "(%s %s %s)" % (
@@ -2391,7 +2620,9 @@ class IntBinopNode(NumBinopNode):
     #  Binary operation taking integer arguments.
     
     def c_types_okay(self, type1, type2):
-        return type1.is_int and type2.is_int
+        #print "IntBinopNode.c_types_okay:", type1, type2 ###
+        return (type1.is_int or type1.is_enum) \
+            and (type2.is_int or type2.is_enum)
 
     
 class AddNode(NumBinopNode):
@@ -2405,9 +2636,10 @@ class AddNode(NumBinopNode):
             return NumBinopNode.is_py_operation(self)
 
     def compute_c_result_type(self, type1, type2):
-        if type1.is_ptr and type2.is_int:
+        #print "AddNode.compute_c_result_type:", type1, self.operator, type2 ###
+        if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
             return type1
-        elif type1.is_int and type2.is_ptr:
+        elif (type2.is_ptr or type2.is_array) and (type1.is_int or type1.is_enum):
             return type2
         else:
             return NumBinopNode.compute_c_result_type(
@@ -2418,9 +2650,9 @@ class SubNode(NumBinopNode):
     #  '-' operator.
     
     def compute_c_result_type(self, type1, type2):
-        if type1.is_ptr and type2.is_int:
+        if (type1.is_ptr or type1.is_array) and (type2.is_int or type2.is_enum):
             return type1
-        elif type1.is_ptr and type2.is_ptr:
+        elif (type1.is_ptr or type1.is_array) and (type2.is_ptr or type2.is_array):
             return PyrexTypes.c_int_type
         else:
             return NumBinopNode.compute_c_result_type(
@@ -2479,6 +2711,14 @@ class BoolBinopNode(ExprNode):
     
     subexprs = ['operand1', 'operand2', 'temp_bool']
     
+    def compile_time_value(self, denv):
+        if self.operator == 'and':
+            return self.operand1.compile_time_value(denv) \
+                and self.operand2.compile_time_value(denv)
+        else:
+            return self.operand1.compile_time_value(denv) \
+                or self.operand2.compile_time_value(denv)
+
     def analyse_types(self, env):
         self.operand1.analyse_types(env)
         self.operand2.analyse_types(env)
@@ -2571,6 +2811,19 @@ class CmpNode:
     #  Mixin class containing code common to PrimaryCmpNodes
     #  and CascadedCmpNodes.
     
+    def cascaded_compile_time_value(self, operand1, denv):
+        func = get_compile_time_binop(self)
+        operand2 = self.operand.compile_time_value(denv)
+        try:
+            result = func(operand1, operand2)
+        except Exception, e:
+            self.compile_time_value_error(e)
+        if result:
+            cascade = self.cascade
+            if cascade:
+                result = result and cascade.compile_time_value(operand2, denv)
+        return result
+
     def is_python_comparison(self):
         return (self.has_python_operands()
             or (self.cascade and self.cascade.is_python_comparison())
@@ -2626,11 +2879,20 @@ class CmpNode:
                     "%s = %s %s 0;" % (
                         result_code, result_code, op))
         else:
+            type1 = operand1.type
+            type2 = operand2.type
+            if (type1.is_extension_type or type2.is_extension_type) \
+                    and not type1.same_as(type2):
+                common_type = py_object_type
+            else:
+                common_type = type1
+            code1 = operand1.result_as(common_type)
+            code2 = operand2.result_as(common_type)
             code.putln("%s = %s %s %s;" % (
                 result_code, 
-                operand1.result_code
+                code1
                 self.c_operator(op), 
-                operand2.result_code))
+                code2))
     
     def c_operator(self, op):
         if op == 'is':
@@ -2657,6 +2919,10 @@ class PrimaryCmpNode(ExprNode, CmpNode):
     
     cascade = None
     
+    def compile_time_value(self, denv):
+        operand1 = self.operand.compile_time_value(denv)
+        return self.cascaded_compile_time_value(operand1, denv)
+
     def analyse_types(self, env):
         self.operand1.analyse_types(env)
         self.operand2.analyse_types(env)
@@ -2937,9 +3203,14 @@ class CoerceFromPyTypeNode(CoercionNode):
         rhs = "%s(%s)" % (function, operand)
         if self.type.is_enum:
             rhs = typecast(self.type, c_long_type, rhs)
-        code.putln('%s = %s; if (PyErr_Occurred()) %s' % (
+        if self.type.is_string:
+            err_code = "!%s" % self.result_code
+        else:
+            err_code = "PyErr_Occurred()"
+        code.putln('%s = %s; if (%s) %s' % (
             self.result_code, 
-            rhs, 
+            rhs,
+            err_code,
             code.error_goto(self.pos)))
 
 
@@ -3095,42 +3366,42 @@ bad:
 }]
 
 #------------------------------------------------------------------------------------
-
-get_exception_utility_code = [
-"""
-static PyObject *__Pyx_GetExcValue(void); /*proto*/
-""","""
-static PyObject *__Pyx_GetExcValue(void) {
-    PyObject *type = 0, *value = 0, *tb = 0;
-    PyObject *result = 0;
-    PyThreadState *tstate = PyThreadState_Get();
-    PyErr_Fetch(&type, &value, &tb);
-    PyErr_NormalizeException(&type, &value, &tb);
-    if (PyErr_Occurred())
-        goto bad;
-    if (!value) {
-        value = Py_None;
-        Py_INCREF(value);
-    }
-    Py_XDECREF(tstate->exc_type);
-    Py_XDECREF(tstate->exc_value);
-    Py_XDECREF(tstate->exc_traceback);
-    tstate->exc_type = type;
-    tstate->exc_value = value;
-    tstate->exc_traceback = tb;
-    result = value;
-    Py_XINCREF(result);
-    type = 0;
-    value = 0;
-    tb = 0;
-bad:
-    Py_XDECREF(type);
-    Py_XDECREF(value);
-    Py_XDECREF(tb);
-    return result;
-}
-"""]
-
+#
+#get_exception_utility_code = [
+#"""
+#static PyObject *__Pyx_GetExcValue(void); /*proto*/
+#""","""
+#static PyObject *__Pyx_GetExcValue(void) {
+#      PyObject *type = 0, *value = 0, *tb = 0;
+#      PyObject *result = 0;
+#      PyThreadState *tstate = PyThreadState_Get();
+#      PyErr_Fetch(&type, &value, &tb);
+#      PyErr_NormalizeException(&type, &value, &tb);
+#      if (PyErr_Occurred())
+#              goto bad;
+#      if (!value) {
+#              value = Py_None;
+#              Py_INCREF(value);
+#      }
+#      Py_XDECREF(tstate->exc_type);
+#      Py_XDECREF(tstate->exc_value);
+#      Py_XDECREF(tstate->exc_traceback);
+#      tstate->exc_type = type;
+#      tstate->exc_value = value;
+#      tstate->exc_traceback = tb;
+#      result = value;
+#      Py_XINCREF(result);
+#      type = 0;
+#      value = 0;
+#      tb = 0;
+#bad:
+#      Py_XDECREF(type);
+#      Py_XDECREF(value);
+#      Py_XDECREF(tb);
+#      return result;
+#}
+#"""]
+#
 #------------------------------------------------------------------------------------
 
 unpacking_utility_code = [
index 254c80373c1580d873e2c956a339ad1b57166494..b3f987c01fd5b845c5119d49952e214d0e34d2f5 100644 (file)
@@ -17,6 +17,8 @@ import Parsing
 from Symtab import BuiltinScope, ModuleScope
 import Code
 from Pyrex.Utils import replace_suffix
+import Builtin
+from Pyrex import Utils
 
 verbose = 0
 
@@ -31,7 +33,8 @@ class Context:
     #  include_directories   [string]
     
     def __init__(self, include_directories):
-        self.modules = {"__builtin__" : BuiltinScope()}
+        #self.modules = {"__builtin__" : BuiltinScope()}
+        self.modules = {"__builtin__" : Builtin.builtin_scope}
         self.include_directories = include_directories
         
     def find_module(self, module_name, 
@@ -171,22 +174,29 @@ class Context:
             else:
                 c_suffix = ".c"
             result.c_file = replace_suffix(source, c_suffix)
+        c_stat = None
+        if result.c_file:
+            try:
+                c_stat = os.stat(result.c_file)
+            except EnvironmentError:
+                pass
         module_name = self.extract_module_name(source)
         initial_pos = (source, 1, 0)
         scope = self.find_module(module_name, pos = initial_pos, need_pxd = 0)
         errors_occurred = False
         try:
             tree = self.parse(source, scope.type_names, pxd = 0)
-            tree.process_implementation(scope, result)
+            tree.process_implementation(scope, options, result)
         except CompileError:
             errors_occurred = True
         Errors.close_listing_file()
         result.num_errors = Errors.num_errors
         if result.num_errors > 0:
             errors_occurred = True
-        if errors_occurred:
+        if errors_occurred and result.c_file:
             try:
-                os.unlink(result.c_file)
+                #os.unlink(result.c_file)
+                Utils.castrate_file(result.c_file, c_stat)
             except EnvironmentError:
                 pass
             result.c_file = None
@@ -216,6 +226,7 @@ class CompilationOptions:
     errors_to_stderr  boolean   Echo errors to stderr when using .lis
     include_path      [string]  Directories to search for include files
     output_file       string    Name of generated .c file
+    generate_pxi      boolean   Generate .pxi file for public declarations
     
     Following options are experimental and only used on MacOSX:
     
@@ -229,7 +240,11 @@ class CompilationOptions:
         self.include_path = []
         self.objects = []
         if defaults:
-            self.__dict__.update(defaults.__dict__)
+            if isinstance(defaults, CompilationOptions):
+                defaults = defaults.__dict__
+        else:
+            defaults = default_options
+        self.__dict__.update(defaults)
         self.__dict__.update(kw)
 
 
@@ -240,6 +255,7 @@ class CompilationResult:
     c_file           string or None   The generated C source file
     h_file           string or None   The generated C header file
     i_file           string or None   The generated .pxi file
+    api_file         string or None   The generated C API .h file
     listing_file     string or None   File of error messages
     object_file      string or None   Result of compiling the C file
     extension_file   string or None   Result of linking the object file
@@ -250,6 +266,7 @@ class CompilationResult:
         self.c_file = None
         self.h_file = None
         self.i_file = None
+        self.api_file = None
         self.listing_file = None
         self.object_file = None
         self.extension_file = None
@@ -307,18 +324,19 @@ def main(command_line = 0):
 #
 #------------------------------------------------------------------------
 
-default_options = CompilationOptions(
+default_options = dict(
     show_version = 0,
     use_listing_file = 0,
     errors_to_stderr = 1,
     c_only = 1,
     obj_only = 1,
     cplus = 0,
-    output_file = None)
+    output_file = None,
+    generate_pxi = 0)
     
 if sys.platform == "mac":
     from Pyrex.Mac.MacSystem import c_compile, c_link, CCompilerError
-    default_options.use_listing_file = 1
+    default_options['use_listing_file'] = 1
 elif sys.platform == "darwin":
     from Pyrex.Mac.DarwinSystem import c_compile, c_link, CCompilerError
 else:
index 3760e5c546cb471c312b5a479cdacdcf8fb274d4..fa392d13e87bcc344fa525908474ed69f0e8d3c4 100644 (file)
@@ -4,6 +4,7 @@
 
 import os, time
 from cStringIO import StringIO
+from PyrexTypes import CPtrType
 
 import Code
 import Naming
@@ -20,55 +21,169 @@ from Pyrex.Utils import open_new_file, replace_suffix
 class ModuleNode(Nodes.Node, Nodes.BlockNode):
     #  doc       string or None
     #  body      StatListNode
+    #
+    #  referenced_modules   [ModuleScope]
+    #  module_temp_cname    string
     
     def analyse_declarations(self, env):
         env.doc = self.doc
         self.body.analyse_declarations(env)
     
-    def process_implementation(self, env, result):
+    def process_implementation(self, env, options, result):
         self.analyse_declarations(env)
         env.check_c_classes()
         self.body.analyse_expressions(env)
         env.return_type = PyrexTypes.c_void_type
+        self.referenced_modules = []
+        self.find_referenced_modules(env, self.referenced_modules, {})
+        if self.has_imported_c_functions():
+            self.module_temp_cname = env.allocate_temp_pyobject()
+            env.release_temp(self.module_temp_cname)
         self.generate_c_code(env, result)
-        self.generate_h_code(env, result)
+        self.generate_h_code(env, options, result)
+        self.generate_api_code(env, result)
     
-    def generate_h_code(self, env, result):
-        public_vars_and_funcs = []
+    def has_imported_c_functions(self):
+        for module in self.referenced_modules:
+            for entry in module.cfunc_entries:
+                if entry.defined_in_pxd:
+                    return 1
+        return 0
+    
+    def generate_h_code(self, env, options, result):
+        public_vars = []
+        public_funcs = []
         public_extension_types = []
         for entry in env.var_entries:
             if entry.visibility == 'public':
-                public_vars_and_funcs.append(entry)
+                public_vars.append(entry)
         for entry in env.cfunc_entries:
             if entry.visibility == 'public':
-                public_vars_and_funcs.append(entry)
+                public_funcs.append(entry)
         for entry in env.c_class_entries:
             if entry.visibility == 'public':
                 public_extension_types.append(entry)
-        if public_vars_and_funcs or public_extension_types:
+        if public_vars or public_funcs or public_extension_types:
             result.h_file = replace_suffix(result.c_file, ".h")
-            result.i_file = replace_suffix(result.c_file, ".pxi")
             h_code = Code.CCodeWriter(open_new_file(result.h_file))
-            i_code = Code.PyrexCodeWriter(result.i_file)
+            if options.generate_pxi:
+                result.i_file = replace_suffix(result.c_file, ".pxi")
+                i_code = Code.PyrexCodeWriter(result.i_file)
+            else:
+                i_code = None
+            guard = Naming.h_guard_prefix + env.qualified_name.replace(".", "__")
+            h_code.put_h_guard(guard)
             self.generate_extern_c_macro_definition(h_code)
-            for entry in public_vars_and_funcs:
-                h_code.putln("%s %s;" % (
-                    Naming.extern_c_macro,
-                    entry.type.declaration_code(
-                        entry.cname, dll_linkage = "DL_IMPORT")))
-                i_code.putln("cdef extern %s" % 
-                    entry.type.declaration_code(entry.cname, pyrex = 1))
-            for entry in public_extension_types:
-                self.generate_cclass_header_code(entry.type, h_code)
-                self.generate_cclass_include_code(entry.type, i_code)
+            self.generate_type_header_code(env, h_code)
+            h_code.putln("")
+            h_code.putln("#ifndef %s" % Naming.api_guard_prefix + self.api_name(env))
+            if public_vars:
+                h_code.putln("")
+                for entry in public_vars:
+                    self.generate_public_declaration(entry, h_code, i_code)
+            if public_funcs:
+                h_code.putln("")
+                for entry in public_funcs:
+                    self.generate_public_declaration(entry, h_code, i_code)
+            if public_extension_types:
+                h_code.putln("")
+                for entry in public_extension_types:
+                    self.generate_cclass_header_code(entry.type, h_code)
+                    if i_code:
+                        self.generate_cclass_include_code(entry.type, i_code)
+            h_code.putln("")
+            h_code.putln("#endif")
+            h_code.putln("")
             h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name)
+            h_code.putln("")
+            h_code.putln("#endif")
+    
+    def generate_public_declaration(self, entry, h_code, i_code):
+        h_code.putln("%s %s;" % (
+            Naming.extern_c_macro,
+            entry.type.declaration_code(
+                entry.cname, dll_linkage = "DL_IMPORT")))
+        if i_code:
+            i_code.putln("cdef extern %s" % 
+                entry.type.declaration_code(entry.cname, pyrex = 1))
+    
+    def api_name(self, env):
+        return env.qualified_name.replace(".", "__")
+    
+    def generate_api_code(self, env, result):
+        api_funcs = []
+        for entry in env.cfunc_entries:
+            if entry.api:
+                api_funcs.append(entry)
+        public_extension_types = []
+        for entry in env.c_class_entries:
+            if entry.visibility == 'public':
+                public_extension_types.append(entry)
+        if api_funcs or public_extension_types:
+            result.api_file = replace_suffix(result.c_file, "_api.h")
+            h_code = Code.CCodeWriter(open_new_file(result.api_file))
+            name = self.api_name(env)
+            guard = Naming.api_guard_prefix + name
+            h_code.put_h_guard(guard)
+            h_code.putln('#include "Python.h"')
+            if result.h_file:
+                h_code.putln('#include "%s"' % os.path.basename(result.h_file))
+            for entry in public_extension_types:
+                type = entry.type
+                h_code.putln("")
+                h_code.putln("static PyTypeObject *%s;" % type.typeptr_cname)
+                h_code.putln("#define %s (*%s)" % (
+                    type.typeobj_cname, type.typeptr_cname))
+            if api_funcs:
+                h_code.putln("")
+                for entry in api_funcs:
+                    type = CPtrType(entry.type)
+                    h_code.putln("static %s;" % type.declaration_code(entry.cname))
+            h_code.putln("")
+            h_code.put_h_guard(Naming.api_func_guard + "import_module")
+            h_code.put(import_module_utility_code[1])
+            h_code.putln("")
+            h_code.putln("#endif")
+            if api_funcs:
+                h_code.putln("")
+                h_code.put_h_guard(Naming.api_func_guard + "import_function")
+                h_code.put(function_import_utility_code[1])
+                h_code.putln("")
+                h_code.putln("#endif")
+            if public_extension_types:
+                h_code.putln("")
+                h_code.put_h_guard(Naming.api_func_guard + "import_type")
+                h_code.put(type_import_utility_code[1])
+                h_code.putln("")
+                h_code.putln("#endif")
+            h_code.putln("")
+            h_code.putln("static int import_%s(void) {" % name)
+            h_code.putln("PyObject *module = 0;")
+            h_code.putln('module = __Pyx_ImportModule("%s");' % env.qualified_name)
+            h_code.putln("if (!module) goto bad;")
+            for entry in api_funcs:
+                sig = entry.type.signature_string()
+                h_code.putln(
+                    'if (__Pyx_ImportFunction(module, "%s", (void**)&%s, "%s") < 0) goto bad;' % (
+                        entry.name,
+                        entry.cname,
+                        sig))
+            h_code.putln("Py_DECREF(module);")
+            for entry in public_extension_types:
+                self.generate_type_import_call(entry.type, h_code, "goto bad")
+            h_code.putln("return 0;")
+            h_code.putln("bad:")
+            h_code.putln("Py_XDECREF(module);")
+            h_code.putln("return -1;")
+            h_code.putln("}")
+            h_code.putln("")
+            h_code.putln("#endif")
     
     def generate_cclass_header_code(self, type, h_code):
-        #h_code.putln("extern DL_IMPORT(PyTypeObject) %s;" % type.typeobj_cname)
         h_code.putln("%s DL_IMPORT(PyTypeObject) %s;" % (
             Naming.extern_c_macro,
             type.typeobj_cname))
-        self.generate_obj_struct_definition(type, h_code)
+        #self.generate_obj_struct_definition(type, h_code)
     
     def generate_cclass_include_code(self, type, i_code):
         i_code.putln("cdef extern class %s.%s:" % (
@@ -84,9 +199,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         i_code.dedent()
     
     def generate_c_code(self, env, result):
-        modules = []
-        self.find_referenced_modules(env, modules, {})
-        #code = Code.CCodeWriter(result.c_file)
+#              modules = []
+#              self.find_referenced_modules(env, modules, {})
+        modules = self.referenced_modules
         code = Code.CCodeWriter(StringIO())
         code.h = Code.CCodeWriter(StringIO())
         code.init_labels()
@@ -129,22 +244,28 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         code.putln('/* Generated by Pyrex %s on %s */' % (
             Version.version, time.asctime()))
         code.putln('')
+        code.putln('#define PY_SSIZE_T_CLEAN')
         for filename in env.python_include_files:
             code.putln('#include "%s"' % filename)
         code.putln("#ifndef PY_LONG_LONG")
         code.putln("  #define PY_LONG_LONG LONG_LONG")
         code.putln("#endif")
+        code.putln("#if PY_VERSION_HEX < 0x02050000")
+        code.putln("  typedef int Py_ssize_t;")
+        code.putln("  #define PY_SSIZE_T_MAX INT_MAX")
+        code.putln("  #define PY_SSIZE_T_MIN INT_MIN")
+        code.putln("  #define PyInt_FromSsize_t(z) PyInt_FromLong(z)")
+        code.putln("  #define PyInt_AsSsize_t(o)       PyInt_AsLong(o)")
+        code.putln("#endif")
+        code.putln("#ifndef WIN32")
+        code.putln("  #define __stdcall")
+        code.putln("  #define __cdecl")
+        code.putln("#endif")
         self.generate_extern_c_macro_definition(code)
-        code.putln("%s double pow(double, double);" % Naming.extern_c_macro)
+        code.putln("#include <math.h>")
         self.generate_includes(env, cimported_modules, code)
-        #for filename in env.include_files:
-        #      code.putln('#include "%s"' % filename)
         code.putln('')
         code.put(Nodes.utility_function_predeclarations)
-        #if Options.intern_names:
-        #      code.putln(Nodes.get_name_interned_predeclaration)
-        #else:
-        #      code.putln(get_name_predeclaration)
         code.putln('')
         code.putln('static PyObject *%s;' % env.module_cname)
         code.putln('static PyObject *%s;' % Naming.builtins_cname)
@@ -192,28 +313,65 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         self.generate_type_predeclarations(env, code)
         self.generate_type_definitions(env, code)
         self.generate_global_declarations(env, code, definition)
-        self.generate_cfunction_predeclarations(env, code)
+        self.generate_cfunction_predeclarations(env, code, definition)
 
     def generate_type_predeclarations(self, env, code):
         pass
     
-    def generate_type_definitions(self, env, code):
-        # Generate definitions of structs/unions/enums.
-        for entry in env.sue_entries:
+    def generate_type_header_code(self, env, code):
+        # Generate definitions of structs/unions/enums/typedefs/objstructs.
+        #self.generate_gcc33_hack(env, code) # Is this still needed?
+        for entry in env.type_entries:
             if not entry.in_cinclude:
+                #print "generate_type_header_code:", entry.name, repr(entry.type) ###
                 type = entry.type
-                if type.is_struct_or_union:
+                if type.is_typedef: # Must test this first!
+                    self.generate_typedef(entry, code)
+                elif type.is_struct_or_union:
                     self.generate_struct_union_definition(entry, code)
-                else:
+                elif type.is_enum:
                     self.generate_enum_definition(entry, code)
+                elif type.is_extension_type:
+                    self.generate_obj_struct_definition(type, code)
+    
+    def generate_type_definitions(self, env, code):
+        # Generate definitions of structs/unions/enums.
+#              self.generate_gcc33_hack(env, code)
+#              for entry in env.sue_entries:
+#                      if not entry.in_cinclude:
+#                              type = entry.type
+#                              if type.is_struct_or_union:
+#                                      self.generate_struct_union_definition(entry, code)
+#                              else:
+#                                      self.generate_enum_definition(entry, code)
+        self.generate_type_header_code(env, code)
         # Generate extension type object struct definitions.
         for entry in env.c_class_entries:
             if not entry.in_cinclude:
                 self.generate_typeobject_predeclaration(entry, code)
-                self.generate_obj_struct_definition(entry.type, code)
+                #self.generate_obj_struct_definition(entry.type, code)
                 self.generate_exttype_vtable_struct(entry, code)
                 self.generate_exttype_vtabptr_declaration(entry, code)
     
+    def generate_gcc33_hack(self, env, code):
+        # Workaround for spurious warning generation in gcc 3.3
+        code.putln("")
+        for entry in env.c_class_entries:
+            type = entry.type
+            if not type.typedef_flag:
+                name = type.objstruct_cname
+                if name.startswith("__pyx_"):
+                    tail = name[6:]
+                else:
+                    tail = name
+                code.putln("typedef struct %s __pyx_gcc33_%s;" % (
+                    name, tail))
+    
+    def generate_typedef(self, entry, code):
+        base_type = entry.type.typedef_base_type
+        code.putln("")
+        code.putln("typedef %s;" % base_type.declaration_code(entry.cname))
+
     def sue_header_footer(self, type, kind, name):
         if type.typedef_flag:
             header = "typedef %s {" % kind
@@ -342,7 +500,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 "%s;" %
                     attr.type.declaration_code(attr.cname))
         code.putln(footer)
-
+    
     def generate_global_declarations(self, env, code, definition):
         code.putln("")
         for entry in env.c_class_entries:
@@ -352,14 +510,18 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             dll_linkage = "DL_EXPORT", definition = definition)
         code.put_var_declarations(env.default_entries, static = 1)
     
-    def generate_cfunction_predeclarations(self, env, code):
+    def generate_cfunction_predeclarations(self, env, code, definition):
         for entry in env.cfunc_entries:
-            if not entry.in_cinclude:
-                if entry.visibility == 'public':
+            if not entry.in_cinclude and (definition
+                    or entry.defined_in_pxd or entry.visibility == 'extern'):
+                if entry.visibility in ('public', 'extern'):
                     dll_linkage = "DL_EXPORT"
                 else:
                     dll_linkage = None
-                header = entry.type.declaration_code(entry.cname, 
+                type = entry.type
+                if not definition and entry.defined_in_pxd:
+                    type = CPtrType(type)
+                header = type.declaration_code(entry.cname, 
                     dll_linkage = dll_linkage)
                 if entry.visibility <> 'private':
                     storage_class = "%s " % Naming.extern_c_macro
@@ -419,11 +581,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 type.declaration_code("")))
     
     def generate_new_function(self, scope, code):
-        base_type = scope.parent_type.base_type
+        type = scope.parent_type
+        base_type = type.base_type
+        py_attrs = []
+        for entry in scope.var_entries:
+            if entry.type.is_pyobject:
+                py_attrs.append(entry)
+        need_self_cast = type.vtabslot_cname or py_attrs
         code.putln("")
         code.putln(
             "static PyObject *%s(PyTypeObject *t, PyObject *a, PyObject *k) {"
                 % scope.mangle_internal("tp_new"))
+        if need_self_cast:
+            code.putln(
+                "%s;"
+                    % scope.parent_type.declaration_code("p"))
         if base_type:
             code.putln(
                 "PyObject *o = %s->tp_new(t, a, k);" %
@@ -431,13 +603,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         else:
             code.putln(
                 "PyObject *o = (*t->tp_alloc)(t, 0);")
-        type = scope.parent_type
-        py_attrs = []
-        for entry in scope.var_entries:
-            if entry.type.is_pyobject:
-                py_attrs.append(entry)
-        if type.vtabslot_cname or py_attrs:
-            self.generate_self_cast(scope, code)
+        code.putln(
+                "if (!o) return 0;")
+        if need_self_cast:
+            code.putln(
+                "p = %s;"
+                    % type.cast_code("o"))
+        #if need_self_cast:
+        #      self.generate_self_cast(scope, code)
         if type.vtabslot_cname:
             code.putln("*(struct %s **)&p->%s = %s;" % (
                 type.vtabstruct_cname,
@@ -519,7 +692,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 % scope.mangle_internal("tp_traverse"))
         py_attrs = []
         for entry in scope.var_entries:
-            if entry.type.is_pyobject:
+            if entry.type.is_pyobject and entry.name <> "__weakref__":
                 py_attrs.append(entry)
         if base_type or py_attrs:
             code.putln(
@@ -555,7 +728,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
                 % scope.mangle_internal("tp_clear"))
         py_attrs = []
         for entry in scope.var_entries:
-            if entry.type.is_pyobject:
+            if entry.type.is_pyobject and entry.name <> "__weakref__":
                 py_attrs.append(entry)
         if py_attrs:
             self.generate_self_cast(scope, code)
@@ -577,12 +750,12 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         # a __getitem__ method is present. It converts its
         # argument to a Python integer and calls mp_subscript.
         code.putln(
-            "static PyObject *%s(PyObject *o, int i) {" %
+            "static PyObject *%s(PyObject *o, Py_ssize_t i) {" %
                 scope.mangle_internal("sq_item"))
         code.putln(
                 "PyObject *r;")
         code.putln(
-                "PyObject *x = PyInt_FromLong(i); if(!x) return 0;")
+                "PyObject *x = PyInt_FromSsize_t(i); if(!x) return 0;")
         code.putln(
                 "r = o->ob_type->tp_as_mapping->mp_subscript(o, x);")
         code.putln(
@@ -668,7 +841,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         del_entry = scope.lookup_here("__delslice__")
         code.putln("")
         code.putln(
-            "static int %s(PyObject *o, int i, int j, PyObject *v) {" %
+            "static int %s(PyObject *o, Py_ssize_t i, Py_ssize_t j, PyObject *v) {" %
                 scope.mangle_internal("sq_ass_slice"))
         code.putln(
                 "if (v) {")
@@ -1045,17 +1218,29 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         code.putln("%s; /*proto*/" % header)
         code.putln("%s {" % header)
         code.put_var_declarations(env.temp_entries)
+
         #code.putln("/*--- Libary function declarations ---*/")
         env.generate_library_function_declarations(code)
         self.generate_filename_init_call(code)
+
         #code.putln("/*--- Module creation code ---*/")
         self.generate_module_creation_code(env, code)
+
         #code.putln("/*--- Intern code ---*/")
         self.generate_intern_code(env, code)
+
         #code.putln("/*--- String init code ---*/")
         self.generate_string_init_code(env, code)
+
         #code.putln("/*--- Global init code ---*/")
         self.generate_global_init_code(env, code)
+        
+        #code.putln("/*--- Function export code ---*/")
+        self.generate_c_function_export_code(env, code)
+
+        #code.putln("/*--- Function import code ---*/")
+        for module in imported_modules:
+            self.generate_c_function_import_code_for_module(module, env, code)
 
         #code.putln("/*--- Type init code ---*/")
         self.generate_type_init_code(env, code)
@@ -1129,14 +1314,53 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             if entry.visibility <> 'extern':
                 if entry.type.is_pyobject:
                     code.put_init_var_to_py_none(entry)
+
+    def generate_c_function_export_code(self, env, code):
+        # Generate code to create PyCFunction wrappers for exported C functions.
+        for entry in env.cfunc_entries:
+            if entry.api or entry.defined_in_pxd:
+                env.use_utility_code(function_export_utility_code)
+                signature = entry.type.signature_string()
+                code.putln('if (__Pyx_ExportFunction("%s", (void*)%s, "%s") < 0) %s' % (
+                    entry.name,
+                    entry.cname,
+                    signature, 
+                    code.error_goto(self.pos)))
     
     def generate_type_import_code_for_module(self, module, env, code):
-        # Generate type import code for all extension types in
+        # Generate type import code for all exported extension types in
         # an imported module.
-        if module.c_class_entries:
-            for entry in module.c_class_entries:
+        #if module.c_class_entries:
+        for entry in module.c_class_entries:
+            if entry.defined_in_pxd:
                 self.generate_type_import_code(env, entry.type, entry.pos, code)
     
+    def generate_c_function_import_code_for_module(self, module, env, code):
+        # Generate import code for all exported C functions in a cimported module.
+        entries = []
+        for entry in module.cfunc_entries:
+            if entry.defined_in_pxd:
+                entries.append(entry)
+        if entries:
+            env.use_utility_code(import_module_utility_code)
+            env.use_utility_code(function_import_utility_code)
+            temp = self.module_temp_cname
+            code.putln(
+                '%s = __Pyx_ImportModule("%s"); if (!%s) %s' % (
+                    temp,
+                    module.qualified_name,
+                    temp,
+                    code.error_goto(self.pos)))
+            for entry in entries:
+                code.putln(
+                    'if (__Pyx_ImportFunction(%s, "%s", (void**)&%s, "%s") < 0) %s' % (
+                        temp,
+                        entry.name,
+                        entry.cname,
+                        entry.type.signature_string(),
+                        code.error_goto(self.pos)))
+            code.putln("Py_DECREF(%s); %s = 0;" % (temp, temp))
+    
     def generate_type_init_code(self, env, code):
         # Generate type import code for extern extension types
         # and type ready code for non-extern ones.
@@ -1156,8 +1380,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
     
     def use_type_import_utility_code(self, env):
         import ExprNodes
-        env.use_utility_code(Nodes.type_import_utility_code)
-        env.use_utility_code(ExprNodes.import_utility_code)
+        env.use_utility_code(type_import_utility_code)
+        env.use_utility_code(import_module_utility_code)
     
     def generate_type_import_code(self, env, type, pos, code):
         # If not already done, generate code to import the typeobject of an
@@ -1169,13 +1393,14 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             objstruct = type.objstruct_cname
         else:
             objstruct = "struct %s" % type.objstruct_cname
-        code.putln('%s = __Pyx_ImportType("%s", "%s", sizeof(%s)); if (!%s) %s' % (
-            type.typeptr_cname,
-            type.module_name, 
-            type.name,
-            objstruct,
-            type.typeptr_cname,
-            code.error_goto(pos)))
+#              code.putln('%s = __Pyx_ImportType("%s", "%s", sizeof(%s)); if (!%s) %s' % (
+#                      type.typeptr_cname,
+#                      type.module_name, 
+#                      type.name,
+#                      objstruct,
+#                      type.typeptr_cname,
+#                      code.error_goto(pos)))
+        self.generate_type_import_call(type, code, code.error_goto(pos))
         self.use_type_import_utility_code(env)
         if type.vtabptr_cname:
             code.putln(
@@ -1186,6 +1411,19 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             env.use_utility_code(Nodes.get_vtable_utility_code)
         env.types_imported[type] = 1
     
+    def generate_type_import_call(self, type, code, error_code):
+        if type.typedef_flag:
+            objstruct = type.objstruct_cname
+        else:
+            objstruct = "struct %s" % type.objstruct_cname
+        code.putln('%s = __Pyx_ImportType("%s", "%s", sizeof(%s)); if (!%s) %s' % (
+            type.typeptr_cname,
+            type.module_name, 
+            type.name,
+            objstruct,
+            type.typeptr_cname,
+            error_code))
+    
     def generate_type_ready_code(self, env, entry, code):
         # Generate a call to PyType_Ready for an extension
         # type defined in this module.
@@ -1243,7 +1481,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
             for meth_entry in type.scope.cfunc_entries:
                 if meth_entry.func_cname:
                     code.putln(
-                        "*(void(**)())&%s.%s = (void(*)())%s;" % (
+                        "*(void(**)(void))&%s.%s = (void(*)(void))%s;" % (
                             type.vtable_cname,
                             meth_entry.cname,
                             meth_entry.func_cname))
@@ -1268,3 +1506,171 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
         for utility_code in env.utility_code_used:
             code.h.put(utility_code[0])
             code.put(utility_code[1])
+
+#------------------------------------------------------------------------------------
+
+#type_import_utility_code = [
+#"""
+#static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, long size);  /*proto*/
+#""","""
+#static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, 
+#      long size) 
+#{
+#      PyObject *py_module_name = 0;
+#      PyObject *py_class_name = 0;
+#      PyObject *py_name_list = 0;
+#      PyObject *py_module = 0;
+#      PyObject *result = 0;
+#      
+#      py_module_name = PyString_FromString(module_name);
+#      if (!py_module_name)
+#              goto bad;
+#      py_class_name = PyString_FromString(class_name);
+#      if (!py_class_name)
+#              goto bad;
+#      py_name_list = PyList_New(1);
+#      if (!py_name_list)
+#              goto bad;
+#      Py_INCREF(py_class_name);
+#      if (PyList_SetItem(py_name_list, 0, py_class_name) < 0)
+#              goto bad;
+#      py_module = __Pyx_Import(py_module_name, py_name_list);
+#      if (!py_module)
+#              goto bad;
+#      result = PyObject_GetAttr(py_module, py_class_name);
+#      if (!result)
+#              goto bad;
+#      if (!PyType_Check(result)) {
+#              PyErr_Format(PyExc_TypeError, 
+#                      "%s.%s is not a type object",
+#                      module_name, class_name);
+#              goto bad;
+#      }
+#      if (((PyTypeObject *)result)->tp_basicsize != size) {
+#              PyErr_Format(PyExc_ValueError, 
+#                      "%s.%s does not appear to be the correct type object",
+#                      module_name, class_name);
+#              goto bad;
+#      }
+#      goto done;
+#bad:
+#      Py_XDECREF(result);
+#      result = 0;
+#done:
+#      Py_XDECREF(py_module_name);
+#      Py_XDECREF(py_class_name);
+#      Py_XDECREF(py_name_list);
+#      return (PyTypeObject *)result;
+#}
+#"""]
+
+#------------------------------------------------------------------------------------
+
+import_module_utility_code = [
+"""
+static PyObject *__Pyx_ImportModule(char *name); /*proto*/
+""","""
+static PyObject *__Pyx_ImportModule(char *name) {
+    PyObject *py_name = 0;
+    
+    py_name = PyString_FromString(name);
+    if (!py_name)
+        goto bad;
+    return PyImport_Import(py_name);
+bad:
+    Py_XDECREF(py_name);
+    return 0;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+type_import_utility_code = [
+"""
+static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, long size);  /*proto*/
+""","""
+static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, 
+    long size) 
+{
+    PyObject *py_module = 0;
+    PyObject *result = 0;
+    
+    py_module = __Pyx_ImportModule(module_name);
+    if (!py_module)
+        goto bad;
+    result = PyObject_GetAttrString(py_module, class_name);
+    if (!result)
+        goto bad;
+    if (!PyType_Check(result)) {
+        PyErr_Format(PyExc_TypeError, 
+            "%s.%s is not a type object",
+            module_name, class_name);
+        goto bad;
+    }
+    if (((PyTypeObject *)result)->tp_basicsize != size) {
+        PyErr_Format(PyExc_ValueError, 
+            "%s.%s does not appear to be the correct type object",
+            module_name, class_name);
+        goto bad;
+    }
+    return (PyTypeObject *)result;
+bad:
+    Py_XDECREF(result);
+    return 0;
+}
+"""]
+
+#------------------------------------------------------------------------------------
+
+function_export_utility_code = [
+"""
+static int __Pyx_ExportFunction(char *n, void *f, char *s); /*proto*/
+""",r"""
+static int __Pyx_ExportFunction(char *n, void *f, char *s) {
+    PyObject *p = 0;
+    p = PyCObject_FromVoidPtrAndDesc(f, s, 0);
+    if (!p)
+        goto bad;
+    if (PyModule_AddObject(%(MODULE)s, n, p) < 0)
+        goto bad;
+    return 0;
+bad:
+    Py_XDECREF(p);
+    return -1;
+}
+""" % {'MODULE': Naming.module_cname}]
+
+#------------------------------------------------------------------------------------
+
+function_import_utility_code = [
+"""
+static int __Pyx_ImportFunction(PyObject *module, char *funcname, void **f, char *sig); /*proto*/
+""","""
+static int __Pyx_ImportFunction(PyObject *module, char *funcname, void **f, char *sig) {
+    PyObject *cobj = 0;
+    char *desc;
+    
+    cobj = PyObject_GetAttrString(module, funcname);
+    if (!cobj) {
+        PyErr_Format(PyExc_ImportError,
+            "%s does not export expected C function %s",
+                PyModule_GetName(module), funcname);
+        goto bad;
+    }
+    desc = (char *)PyCObject_GetDesc(cobj);
+    if (!desc)
+        goto bad;
+    if (strcmp(desc, sig) != 0) {
+        PyErr_Format(PyExc_TypeError,
+            "C function %s.%s has wrong signature (expected %s, got %s)",
+                PyModule_GetName(module), funcname, sig, desc);
+        goto bad;
+    }
+    *f = PyCObject_AsVoidPtr(cobj);
+    Py_DECREF(cobj);
+    return 0;
+bad:
+    Py_XDECREF(cobj);
+    return -1;
+}
+"""]
index cd30bae95486122e68b348200a0565f14e697a78..988a72c3db23cb0cc7b3b32c762ca0686b77a403 100644 (file)
@@ -47,8 +47,20 @@ module_cname     = pyrex_prefix + "m"
 moddoc_cname     = pyrex_prefix + "mdoc"
 methtable_cname  = pyrex_prefix + "methods"
 retval_cname     = pyrex_prefix + "r"
+reqd_kwds_cname  = pyrex_prefix + "reqd_kwds"
 self_cname       = pyrex_prefix + "self"
 stringtab_cname  = pyrex_prefix + "string_tab"
 vtabslot_cname   = pyrex_prefix + "vtab"
 
 extern_c_macro  = pyrex_prefix.upper() + "EXTERN_C"
+
+exc_type_name   = pyrex_prefix + "exc_type"
+exc_value_name  = pyrex_prefix + "exc_value"
+exc_tb_name     = pyrex_prefix + "exc_tb"
+exc_lineno_name = pyrex_prefix + "exc_lineno"
+
+exc_vars = (exc_type_name, exc_value_name, exc_tb_name)
+
+h_guard_prefix   = "__PYX_HAVE__"
+api_guard_prefix = "__PYX_HAVE_API__"
+api_func_guard   = "__PYX_HAVE_API_FUNC_"
index 1c816d4bb6dab413a860adb5423e5ae3d8f0899b..a3a01d46564688923ac94061491434db3cdd0ef5 100644 (file)
@@ -8,7 +8,7 @@ import Code
 from Errors import error, InternalError
 import Naming
 import PyrexTypes
-from PyrexTypes import py_object_type, error_type, CTypedefType
+from PyrexTypes import py_object_type, error_type, CTypedefType, CFuncType
 from Symtab import ModuleScope, LocalScope, \
     StructOrUnionScope, PyClassScope, CClassScope
 from Pyrex.Utils import open_new_file, replace_suffix
@@ -170,7 +170,10 @@ class CDeclaratorNode(Node):
     #      CNameDeclaratorNode of the name being declared 
     #      and type is the type it is being declared as.
     #
-    pass
+    #  calling_convention  string   Calling convention of CFuncDeclaratorNode
+    #                               for which this is a base 
+    
+    calling_convention = ""
 
 
 class CNameDeclaratorNode(CDeclaratorNode):
@@ -201,7 +204,6 @@ class CArrayDeclaratorNode(CDeclaratorNode):
             self.dimension.analyse_const_expression(env)
             if not self.dimension.type.is_int:
                 error(self.dimension.pos, "Array dimension not integer")
-            #size = self.dimension.value
             size = self.dimension.result_code
         else:
             size = None
@@ -211,6 +213,9 @@ class CArrayDeclaratorNode(CDeclaratorNode):
         if base_type.is_pyobject:
             error(self.pos,
                 "Array element cannot be a Python object")
+        if base_type.is_cfunction:
+            error(self.pos,
+                "Array element cannot be a function")
         array_type = PyrexTypes.c_array_type(base_type, size)
         return self.base.analyse(array_type, env)
 
@@ -221,6 +226,8 @@ class CFuncDeclaratorNode(CDeclaratorNode):
     # has_varargs      boolean
     # exception_value  ConstNode
     # exception_check  boolean    True if PyErr_Occurred check needed
+    # nogil            boolean    Can be called without gil
+    # with_gil         boolean    Acquire gil around function body
 
     def analyse(self, return_type, env):
         func_type_args = []
@@ -236,6 +243,9 @@ class CFuncDeclaratorNode(CDeclaratorNode):
             # Catch attempted C-style func(void) decl
             if type.is_void:
                 error(arg_node.pos, "Function argument cannot be void")
+            if type.is_pyobject and self.nogil:
+                error(self.pos,
+                    "Function with Python argument cannot be declared nogil")
             func_type_args.append(
                 PyrexTypes.CFuncTypeArg(name, type, arg_node.pos))
             if arg_node.default:
@@ -254,9 +264,20 @@ class CFuncDeclaratorNode(CDeclaratorNode):
                     error(self.exception_value.pos,
                         "Exception value incompatible with function return type")
             exc_check = self.exception_check
+        if return_type.is_pyobject and self.nogil:
+            error(self.pos,
+                "Function with Python return type cannot be declared nogil")
+        if return_type.is_array:
+            error(self.pos,
+                "Function cannot return an array")
+        if return_type.is_cfunction:
+            error(self.pos,
+                "Function cannot return a function")
         func_type = PyrexTypes.CFuncType(
             return_type, func_type_args, self.has_varargs, 
-            exception_value = exc_val, exception_check = exc_check)
+            exception_value = exc_val, exception_check = exc_check,
+            calling_convention = self.base.calling_convention,
+            nogil = self.nogil, with_gil = self.with_gil)
         return self.base.analyse(func_type, env)
 
 
@@ -269,10 +290,12 @@ class CArgDeclNode(Node):
     # default        ExprNode or None
     # default_entry  Symtab.Entry       Entry for the variable holding the default value
     # is_self_arg    boolean            Is the "self" arg of an extension type method
-    
+    # is_kw_only     boolean            Is a keyword-only argument
+
     is_self_arg = 0
     
     def analyse(self, env):
+        #print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
         base_type = self.base_type.analyse(env)
         return self.declarator.analyse(base_type, env)
 
@@ -298,6 +321,7 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
 
     def analyse(self, env):
         # Return type descriptor.
+        #print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ###
         type = None
         if self.is_basic_c_type:
             type = PyrexTypes.simple_c_type(self.signed, self.longness, self.name)
@@ -307,6 +331,7 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
             type = py_object_type
         elif self.name is None:
             if self.is_self_arg and env.is_c_class_scope:
+                #print "CSimpleBaseTypeNode.analyse: defaulting to parent type" ###
                 type = env.parent_type
             else:
                 type = py_object_type
@@ -349,6 +374,7 @@ class CVarDefNode(StatNode):
     #  visibility    'private' or 'public' or 'extern'
     #  base_type     CBaseTypeNode
     #  declarators   [CDeclaratorNode]
+    #  in_pxd        boolean
     
     def analyse_declarations(self, env, dest_scope = None):
         if not dest_scope:
@@ -366,9 +392,18 @@ class CVarDefNode(StatNode):
             name = name_declarator.name
             cname = name_declarator.cname
             if type.is_cfunction:
-                dest_scope.declare_cfunction(name, type, declarator.pos,
-                    cname = cname, visibility = self.visibility)
+                entry = dest_scope.declare_cfunction(name, type, declarator.pos,
+                    cname = cname, visibility = self.visibility, in_pxd = self.in_pxd)
+                #if self.visibility <> 'extern':
+                #      if self.in_pxd:
+                #              entry.defined_in_pxd = 1
+                #      else:
+                #              error(declarator.pos,
+                #                      "Non-extern C function declared but not defined")
             else:
+                if self.in_pxd and self.visibility <> 'extern':
+                    error(self.pos, 
+                        "Only 'extern' C variable declaration allowed in .pxd file")                                   
                 dest_scope.declare_var(name, type, declarator.pos,
                     cname = cname, visibility = self.visibility, is_cdef = 1)
     
@@ -384,6 +419,7 @@ class CStructOrUnionDefNode(StatNode):
     #  cname         string or None
     #  kind          "struct" or "union"
     #  typedef_flag  boolean
+    #  visibility    "public" or "private"
     #  attributes    [CVarDefNode] or None
     #  entry         Entry
     
@@ -393,7 +429,7 @@ class CStructOrUnionDefNode(StatNode):
             scope = StructOrUnionScope()
         self.entry = env.declare_struct_or_union(
             self.name, self.kind, scope, self.typedef_flag, self.pos,
-            self.cname)
+            self.cname, visibility = self.visibility)
         if self.attributes is not None:
             for attr in self.attributes:
                 attr.analyse_declarations(env, scope)
@@ -410,11 +446,13 @@ class CEnumDefNode(StatNode):
     #  cname          string or None
     #  items          [CEnumDefItemNode]
     #  typedef_flag   boolean
+    #  visibility    "public" or "private"
     #  entry          Entry
     
     def analyse_declarations(self, env):
         self.entry = env.declare_enum(self.name, self.pos,
-            cname = self.cname, typedef_flag = self.typedef_flag)
+            cname = self.cname, typedef_flag = self.typedef_flag,
+            visibility = self.visibility)
         for item in self.items:
             item.analyse_declarations(env, self.entry)
 
@@ -444,15 +482,17 @@ class CEnumDefItemNode(StatNode):
 class CTypeDefNode(StatNode):
     #  base_type   CBaseTypeNode
     #  declarator  CDeclaratorNode
+    #  visibility    "public" or "private"
     
     def analyse_declarations(self, env):
         base = self.base_type.analyse(env)
         name_declarator, type = self.declarator.analyse(base, env)
         name = name_declarator.name
         cname = name_declarator.cname
-        if env.in_cinclude:
-            type = CTypedefType(cname or name, type)
-        env.declare_type(name, type, self.pos, cname = cname)
+        #if env.in_cinclude:
+        #      type = CTypedefType(cname, type)
+        env.declare_typedef(name, type, self.pos,
+            cname = cname, visibility = self.visibility)
     
     def analyse_expressions(self, env):
         pass
@@ -470,14 +510,15 @@ class FuncDefNode(StatNode, BlockNode):
     
     def analyse_expressions(self, env):
         pass
+    
+    def need_gil_acquisition(self, lenv):
+        return 0
                 
     def generate_function_definitions(self, env, code):
         # Generate C code for header and body of function
         genv = env.global_scope()
         lenv = LocalScope(name = self.entry.name, outer_scope = genv)
-        #lenv.function_name = self.function_name()
         lenv.return_type = self.return_type
-        #self.filename = lenv.get_filename_const(self.pos)
         code.init_labels()
         self.declare_arguments(lenv)
         self.body.analyse_declarations(lenv)
@@ -506,6 +547,10 @@ class FuncDefNode(StatNode, BlockNode):
         self.generate_keyword_list(code)
         # ----- Extern library function declarations
         lenv.generate_library_function_declarations(code)
+        # ----- GIL acquisition
+        acquire_gil = self.need_gil_acquisition(lenv)
+        if acquire_gil:
+            code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
         # ----- Fetch arguments
         self.generate_argument_parsing_code(code)
         self.generate_argument_increfs(lenv, code)
@@ -552,18 +597,23 @@ class FuncDefNode(StatNode, BlockNode):
                     '__Pyx_WriteUnraisable("%s");' % 
                         self.entry.qualified_name)
                 env.use_utility_code(unraisable_exception_utility_code)
+                #if not self.return_type.is_void:
+                default_retval = self.return_type.default_value
+                if default_retval:
+                    code.putln(
+                        "%s = %s;" % (
+                            Naming.retval_cname,
+                            default_retval))
+                            #self.return_type.default_value))
         # ----- Return cleanup
         code.put_label(code.return_label)
         code.put_var_decrefs(lenv.var_entries, used_only = 1)
         code.put_var_decrefs(lenv.arg_entries)
         self.put_stararg_decrefs(code)
+        if acquire_gil:
+            code.putln("PyGILState_Release(_save);")
         if not self.return_type.is_void:
-            retval_code = Naming.retval_cname
-            #if self.return_type.is_extension_type:
-            #  retval_code = "((%s)%s) " % (
-            #          self.return_type.declaration_code(""),
-            #          retval_code)
-            code.putln("return %s;" % retval_code)
+            code.putln("return %s;" % Naming.retval_cname)
         code.putln("}")
     
     def put_stararg_decrefs(self, code):
@@ -595,7 +645,9 @@ class CFuncDefNode(FuncDefNode):
     #  base_type     CBaseTypeNode
     #  declarator    CDeclaratorNode
     #  body          StatListNode
+    #  api           boolean
     #
+    #  with_gil      boolean    Acquire GIL around body
     #  type          CFuncType
     
     def unqualified_name(self):
@@ -604,20 +656,21 @@ class CFuncDefNode(FuncDefNode):
     def analyse_declarations(self, env):
         base_type = self.base_type.analyse(env)
         name_declarator, type = self.declarator.analyse(base_type, env)
+        if not type.is_cfunction:
+            error(self.pos, 
+                "Suite attached to non-function declaration")
         # Remember the actual type according to the function header
         # written here, because the type in the symbol table entry
         # may be different if we're overriding a C method inherited
         # from the base type of an extension type.
         self.type = type
-        if not type.is_cfunction:
-            error(self.pos, 
-                "Suite attached to non-function declaration")
         name = name_declarator.name
         cname = name_declarator.cname
         self.entry = env.declare_cfunction(
             name, type, self.pos, 
             cname = cname, visibility = self.visibility,
-            defining = self.body is not None)
+            defining = self.body is not None,
+            api = self.api)
         self.return_type = type.return_type
     
     def declare_arguments(self, env):
@@ -626,6 +679,14 @@ class CFuncDefNode(FuncDefNode):
                 error(arg.pos, "Missing argument name")
             self.declare_argument(env, arg)
             
+    def need_gil_acquisition(self, lenv):
+        with_gil = self.type.with_gil
+        if self.type.nogil and not with_gil:
+            for entry in lenv.var_entries + lenv.temp_entries:
+                if entry.type.is_pyobject:
+                    error(self.pos, "Function declared nogil has Python locals or temporaries")
+        return with_gil
+
     def generate_function_header(self, code, with_pymethdef):
         arg_decls = []
         type = self.type
@@ -704,6 +765,16 @@ class DefNode(FuncDefNode):
     #  assmt   AssignmentNode   Function construction/assignment
     
     assmt = None
+    num_kwonly_args = 0
+    reqd_kw_flags_cname = "0"
+    
+    def __init__(self, pos, **kwds):
+        FuncDefNode.__init__(self, pos, **kwds)
+        n = 0
+        for arg in self.args:
+            if arg.kw_only:
+                n += 1
+        self.num_kwonly_args = n
     
     def analyse_declarations(self, env):
         for arg in self.args:
@@ -781,14 +852,19 @@ class DefNode(FuncDefNode):
                 desc, self.name, len(self.args), expected_str))
     
     def declare_pyfunction(self, env):
-        self.entry = env.declare_pyfunction(self.name, self.pos)
-        self.entry.doc = self.doc
-        self.entry.func_cname = \
-            Naming.func_prefix + env.scope_prefix + self.name
-        self.entry.doc_cname = \
-            Naming.funcdoc_prefix + env.scope_prefix + self.name
-        self.entry.pymethdef_cname = \
-            Naming.pymethdef_prefix + env.scope_prefix + self.name
+        #print "DefNode.declare_pyfunction:", self.name, "in", env ###
+        name = self.name
+        entry = env.declare_pyfunction(self.name, self.pos)
+        self.entry = entry
+        prefix = env.scope_prefix
+        entry.func_cname = \
+            Naming.func_prefix + prefix + name
+        entry.pymethdef_cname = \
+            Naming.pymethdef_prefix + prefix + name
+        if not entry.is_special:
+            entry.doc = self.doc
+            entry.doc_cname = \
+                Naming.funcdoc_prefix + prefix + name
         
     def declare_arguments(self, env):
         for arg in self.args:
@@ -890,6 +966,8 @@ class DefNode(FuncDefNode):
     
     def generate_keyword_list(self, code):
         if self.entry.signature.has_generic_args:
+            reqd_kw_flags = []
+            has_reqd_kwds = False
             code.put(
                 "static char *%s[] = {" %
                     Naming.kwdlist_cname)
@@ -898,13 +976,32 @@ class DefNode(FuncDefNode):
                     code.put(
                         '"%s",' % 
                             arg.name)
+                    if arg.kw_only and not arg.default:
+                        has_reqd_kwds = 1
+                        flag = "1"
+                    else:
+                        flag = "0"
+                    reqd_kw_flags.append(flag)
             code.putln(
                 "0};")
+            if has_reqd_kwds:
+                flags_name = Naming.reqd_kwds_cname
+                self.reqd_kw_flags_cname = flags_name
+                code.putln(
+                    "static char %s[] = {%s};" % (
+                        flags_name,
+                        ",".join(reqd_kw_flags)))
     
     def generate_argument_parsing_code(self, code):
         # Generate PyArg_ParseTuple call for generic
         # arguments, if any.
-        if self.entry.signature.has_generic_args:
+        has_kwonly_args = self.num_kwonly_args > 0
+        has_star_or_kw_args = self.star_arg is not None \
+            or self.starstar_arg is not None or has_kwonly_args
+        if not self.entry.signature.has_generic_args:
+            if has_star_or_kw_args:
+                error(self.pos, "This method cannot have * or keyword arguments")
+        else:
             arg_addrs = []
             arg_formats = []
             default_seen = 0
@@ -919,7 +1016,7 @@ class DefNode(FuncDefNode):
                         if not default_seen:
                             arg_formats.append("|")
                         default_seen = 1
-                    elif default_seen:
+                    elif default_seen and not arg.kw_only:
                         error(arg.pos, "Non-default argument following default argument")
                     arg_addrs.append("&" + arg_entry.cname)
                     format = arg_entry.type.parsetuple_format
@@ -929,9 +1026,9 @@ class DefNode(FuncDefNode):
                         error(arg.pos, 
                             "Cannot convert Python object argument to type '%s'" 
                                 % arg.type)
+            error_return_code = "return %s;" % self.error_value()
             argformat = '"%s"' % string.join(arg_formats, "")
-            has_starargs = self.star_arg is not None or self.starstar_arg is not None
-            if has_starargs:
+            if has_star_or_kw_args:
                 self.generate_stararg_getting_code(code)
             pt_arglist = [Naming.args_cname, Naming.kwds_cname, argformat,
                     Naming.kwdlist_cname] + arg_addrs
@@ -939,8 +1036,7 @@ class DefNode(FuncDefNode):
             code.put(
                 'if (!PyArg_ParseTupleAndKeywords(%s)) ' %
                     pt_argstring)
-            error_return_code = "return %s;" % self.error_value()
-            if has_starargs:
+            if has_star_or_kw_args:
                 code.putln("{")
                 code.put_xdecref(Naming.args_cname, py_object_type)
                 code.put_xdecref(Naming.kwds_cname, py_object_type)
@@ -950,7 +1046,7 @@ class DefNode(FuncDefNode):
                 code.putln("}")
             else:
                 code.putln(error_return_code)
-            
+        
     def put_stararg_decrefs(self, code):
         if self.star_arg or self.starstar_arg:
             code.put_xdecref(Naming.args_cname, py_object_type)
@@ -967,20 +1063,20 @@ class DefNode(FuncDefNode):
             return 0
 
     def generate_stararg_getting_code(self, code):
-        if self.star_arg or self.starstar_arg:
-            if not self.entry.signature.has_generic_args:
-                error(self.pos, "This method cannot have * or ** arguments")
-            star_arg_addr = self.arg_address(self.star_arg)
-            starstar_arg_addr = self.arg_address(self.starstar_arg)
-            code.putln(
-                "if (__Pyx_GetStarArgs(&%s, &%s, %s, %s, %s, %s) < 0) return %s;" % (
-                    Naming.args_cname,
-                    Naming.kwds_cname,
-                    Naming.kwdlist_cname,
-                    len(self.args) - self.entry.signature.num_fixed_args(),
-                    star_arg_addr,
-                    starstar_arg_addr,
-                    self.error_value()))
+        num_kwonly = self.num_kwonly_args
+        nargs = len(self.args) - num_kwonly - self.entry.signature.num_fixed_args()
+        star_arg_addr = self.arg_address(self.star_arg)
+        starstar_arg_addr = self.arg_address(self.starstar_arg)
+        code.putln(
+            "if (__Pyx_GetStarArgs(&%s, &%s, %s, %s, %s, %s, %s) < 0) return %s;" % (
+                Naming.args_cname,
+                Naming.kwds_cname,
+                Naming.kwdlist_cname,
+                nargs,
+                star_arg_addr,
+                starstar_arg_addr,
+                self.reqd_kw_flags_cname,
+                self.error_value()))
     
     def generate_argument_conversion_code(self, code):
         # Generate code to convert arguments from
@@ -1646,11 +1742,10 @@ class RaiseStatNode(StatNode):
             self.exc_value.release_temp(env)
         if self.exc_tb:
             self.exc_tb.release_temp(env)
-        #env.recycle_pending_temps() # TEMPORARY
-        if not (self.exc_type or self.exc_value or self.exc_tb):
-            env.use_utility_code(reraise_utility_code)
-        else:
-            env.use_utility_code(raise_utility_code)
+#              if not (self.exc_type or self.exc_value or self.exc_tb):
+#                      env.use_utility_code(reraise_utility_code)
+#              else:
+        env.use_utility_code(raise_utility_code)
     
     def generate_execution_code(self, code):
         if self.exc_type:
@@ -1687,6 +1782,20 @@ class RaiseStatNode(StatNode):
             code.error_goto(self.pos))
 
 
+class ReraiseStatNode(StatNode):
+
+    def analyse_expressions(self, env):
+        env.use_utility_code(raise_utility_code)
+
+    def generate_execution_code(self, code):
+        vars = code.exc_vars
+        if vars:
+            code.putln("__Pyx_Raise(%s, %s, %s);" % tuple(vars))
+            code.putln(code.error_goto(self.pos))
+        else:
+            error(self.pos, "Reraise not inside except clause")
+        
+
 class AssertStatNode(StatNode):
     #  assert statement
     #
@@ -1705,6 +1814,7 @@ class AssertStatNode(StatNode):
         #env.recycle_pending_temps() # TEMPORARY
     
     def generate_execution_code(self, code):
+        code.putln("#ifndef PYREX_WITHOUT_ASSERTIONS")
         self.cond.generate_evaluation_code(code)
         if self.value:
             self.value.generate_evaluation_code(code)
@@ -1725,7 +1835,7 @@ class AssertStatNode(StatNode):
         self.cond.generate_disposal_code(code)
         if self.value:
             self.value.generate_disposal_code(code)
-
+        code.putln("#endif")
 
 class IfStatNode(StatNode):
     #  if statement
@@ -2020,9 +2130,6 @@ class TryExceptStatNode(StatNode):
             self.else_clause.generate_execution_code(code)
             code.putln(
                 "}")
-        #code.putln(
-        #      "goto %s;" %
-        #              end_label)
         code.put_goto(end_label)
         code.put_label(our_error_label)
         code.put_var_xdecrefs_clear(self.cleanup_list)
@@ -2035,9 +2142,6 @@ class TryExceptStatNode(StatNode):
                     error(except_clause.pos, "Default except clause not last")
             except_clause.generate_handling_code(code, end_label)
         if not default_clause_seen:
-            #code.putln(
-            #  "goto %s;" %
-            #          code.error_label)
             code.put_goto(code.error_label)
         code.put_label(end_label)
 
@@ -2051,6 +2155,7 @@ class ExceptClauseNode(Node):
     #  match_flag     string             result of exception match
     #  exc_value      ExcValueNode       used internally
     #  function_name  string             qualified name of enclosing function
+    #  exc_vars       (string * 3)       local exception variables
     
     def analyse_declarations(self, env):
         if self.target:
@@ -2067,15 +2172,15 @@ class ExceptClauseNode(Node):
             self.match_flag = env.allocate_temp(PyrexTypes.c_int_type)
             self.pattern.release_temp(env)
             env.release_temp(self.match_flag)
-        self.exc_value = ExprNodes.ExcValueNode(self.pos, env)
-        self.exc_value.allocate_temps(env)
+        self.exc_vars = [env.allocate_temp(py_object_type) for i in xrange(3)]
         if self.target:
+            self.exc_value = ExprNodes.ExcValueNode(self.pos, env, self.exc_vars[1])
+            self.exc_value.allocate_temps(env)
             self.target.analyse_target_expression(env, self.exc_value)
-        else:
-            self.exc_value.release_temp(env)
-        #if self.target:
-        #      self.target.release_target_temp(env)
         self.body.analyse_expressions(env)
+        for var in self.exc_vars:
+            env.release_temp(var)
+        env.use_utility_code(get_exception_utility_code)
     
     def generate_handling_code(self, code, end_label):
         code.mark_pos(self.pos)
@@ -2097,15 +2202,18 @@ class ExceptClauseNode(Node):
         # We always have to fetch the exception value even if
         # there is no target, because this also normalises the 
         # exception and stores it in the thread state.
-        self.exc_value.generate_evaluation_code(code)
+        exc_args = "&%s, &%s, &%s" % tuple(self.exc_vars)
+        code.putln("if (__Pyx_GetException(%s) < 0) %s" % (exc_args,
+            code.error_goto(self.pos)))
         if self.target:
+            self.exc_value.generate_evaluation_code(code)
             self.target.generate_assignment_code(self.exc_value, code)
-        else:
-            self.exc_value.generate_disposal_code(code)
+        old_exc_vars = code.exc_vars
+        code.exc_vars = self.exc_vars
         self.body.generate_execution_code(code)
-        #code.putln(
-        #      "goto %s;"
-        #              % end_label)
+        code.exc_vars = old_exc_vars
+        for var in self.exc_vars:
+            code.putln("Py_DECREF(%s);" % var)
         code.put_goto(end_label)
         code.putln(
             "}")
@@ -2116,8 +2224,8 @@ class TryFinallyStatNode(StatNode):
     #
     #  body             StatNode
     #  finally_clause   StatNode
+    #
     #  cleanup_list     [Entry]      temps to clean up on error
-    #  exc_vars         3*(string,)  temps to hold saved exception
     #
     #  The plan is that we funnel all continue, break
     #  return and error gotos into the beginning of the
@@ -2128,6 +2236,8 @@ class TryFinallyStatNode(StatNode):
     #  exception on entry to the finally block and restore
     #  it on exit.
     
+    preserve_exception = 1
+    
     disallow_continue_in_try_finally = 0
     # There doesn't seem to be any point in disallowing
     # continue in the try block, since we have no problem
@@ -2140,15 +2250,15 @@ class TryFinallyStatNode(StatNode):
     def analyse_expressions(self, env):
         self.body.analyse_expressions(env)
         self.cleanup_list = env.free_temp_entries[:]
-        self.exc_vars = (
-            env.allocate_temp(PyrexTypes.py_object_type),
-            env.allocate_temp(PyrexTypes.py_object_type),
-            env.allocate_temp(PyrexTypes.py_object_type))
-        self.lineno_var = \
-            env.allocate_temp(PyrexTypes.c_int_type)
+        #self.exc_vars = (
+        #      env.allocate_temp(PyrexTypes.py_object_type),
+        #      env.allocate_temp(PyrexTypes.py_object_type),
+        #      env.allocate_temp(PyrexTypes.py_object_type))
+        #self.lineno_var = \
+        #      env.allocate_temp(PyrexTypes.c_int_type)
         self.finally_clause.analyse_expressions(env)
-        for var in self.exc_vars:
-            env.release_temp(var)
+        #for var in self.exc_vars:
+        #      env.release_temp(var)
     
     def generate_execution_code(self, code):
         old_error_label = code.error_label
@@ -2168,47 +2278,69 @@ class TryFinallyStatNode(StatNode):
             "}")
         code.putln(
             "/*finally:*/ {")
-        code.putln(
-                "int __pyx_why;")
-        #code.putln(
-        #              "PyObject *%s, *%s, *%s;" %
-        #                      self.exc_vars)
-        #code.putln(
-        #              "int %s;" %
-        #                      self.lineno_var)
-        code.use_label(catch_label)
-        code.putln(
-                "__pyx_why = 0; goto %s;" %
-                    catch_label)
-        for i in range(len(new_labels)):
-            new_label = new_labels[i]
-            if new_label and new_label <> "<try>":
-                if new_label in code.labels_used:
-                    if new_label == new_error_label:
-                        self.put_error_catcher(code, 
-                            new_error_label, i+1, catch_label)
-                    else:
-                            code.putln(
-                                "%s: __pyx_why = %s; goto %s;" % (
-                                    new_label,
-                                    i+1,
-                                    catch_label))
-        code.put_label(catch_label)
+        cases_used = []
+        error_label_used = 0
+        for i, new_label in enumerate(new_labels):
+            if new_label in code.labels_used:
+                cases_used.append(i)
+                if new_label == new_error_label:
+                    error_label_used = 1
+                    error_label_case = i
+        if cases_used:
+            code.putln(
+                    "int __pyx_why;")
+            if error_label_used and self.preserve_exception:
+                code.putln(
+                    "PyObject *%s, *%s, *%s;" % Naming.exc_vars)
+                code.putln(
+                    "int %s;" % Naming.exc_lineno_name)
+            code.use_label(catch_label)
+            code.putln(
+                    "__pyx_why = 0; goto %s;" % catch_label)
+            for i in cases_used:
+                new_label = new_labels[i]
+                #if new_label and new_label <> "<try>":
+                if new_label == new_error_label and self.preserve_exception:
+                    self.put_error_catcher(code, 
+                        new_error_label, i+1, catch_label)
+                else:
+                    code.putln(
+                        "%s: __pyx_why = %s; goto %s;" % (
+                            new_label,
+                            i+1,
+                            catch_label))
+            code.put_label(catch_label)
         code.set_all_labels(old_labels)
+        if error_label_used:
+            code.new_error_label()
+            finally_error_label = code.error_label
         self.finally_clause.generate_execution_code(code)
-        code.putln(
+        if error_label_used:
+            if finally_error_label in code.labels_used and self.preserve_exception:
+                over_label = code.new_label()
+                code.put_goto(over_label);
+                code.put_label(finally_error_label)
+                code.putln("if (__pyx_why == %d) {" % (error_label_case + 1))
+                for var in Naming.exc_vars:
+                    code.putln("Py_XDECREF(%s);" % var)
+                code.putln("}")
+                code.put_goto(old_error_label)
+                code.put_label(over_label)
+            code.error_label = old_error_label
+        if cases_used:
+            code.putln(
                 "switch (__pyx_why) {")
-        for i in range(len(old_labels)):
-            if old_labels[i]:
-                if old_labels[i] == old_error_label:
+            for i in cases_used:
+                old_label = old_labels[i]
+                if old_label == old_error_label and self.preserve_exception:
                     self.put_error_uncatcher(code, i+1, old_error_label)
                 else:
-                    code.use_label(old_labels[i])
+                    code.use_label(old_label)
                     code.putln(
                         "case %s: goto %s;" % (
                             i+1,
-                            old_labels[i]))
-        code.putln(
+                            old_label))
+            code.putln(
                 "}")           
         code.putln(
             "}")
@@ -2223,10 +2355,10 @@ class TryFinallyStatNode(StatNode):
         code.put_var_xdecrefs_clear(self.cleanup_list)
         code.putln(
                 "PyErr_Fetch(&%s, &%s, &%s);" %
-                    self.exc_vars)
+                    Naming.exc_vars)
         code.putln(
                 "%s = %s;" % (
-                    self.lineno_var, Naming.lineno_cname))
+                    Naming.exc_lineno_name, Naming.lineno_cname))
         #code.putln(
         #              "goto %s;" %
         #                      catch_label)
@@ -2240,22 +2372,71 @@ class TryFinallyStatNode(StatNode):
                 i)
         code.putln(
                 "PyErr_Restore(%s, %s, %s);" %
-                    self.exc_vars)
+                    Naming.exc_vars)
         code.putln(
                 "%s = %s;" % (
-                    Naming.lineno_cname, self.lineno_var))
-        for var in self.exc_vars:
+                    Naming.lineno_cname, Naming.exc_lineno_name))
+        for var in Naming.exc_vars:
             code.putln(
                 "%s = 0;" %
                     var)
-        #code.putln(
-        #              "goto %s;" %
-        #                      error_label)
         code.put_goto(error_label)
         code.putln(
             "}")
 
 
+class GILStatNode(TryFinallyStatNode):
+    #  'with gil' or 'with nogil' statement
+    #
+    #   state   string   'gil' or 'nogil'
+        
+    preserve_exception = 0
+
+    def __init__(self, pos, state, body):
+        self.state = state
+        TryFinallyStatNode.__init__(self, pos,
+            body = body,
+            finally_clause = GILExitNode(pos, state = state))
+
+    def generate_execution_code(self, code):
+        code.putln("/*with %s:*/ {" % self.state)
+        if self.state == 'gil':
+            code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
+        else:
+            code.putln("PyThreadState *_save;")
+            code.putln("Py_UNBLOCK_THREADS")
+        TryFinallyStatNode.generate_execution_code(self, code)
+        code.putln("}")
+
+#class GILEntryNode(StatNode):
+#      #  state   string   'gil' or 'nogil'
+#
+#      def analyse_expressions(self, env):
+#              pass
+#
+#      def generate_execution_code(self, code):
+#              if self.state == 'gil':
+#                      code.putln("PyGILState_STATE _save = PyGILState_Ensure();")
+#              else:
+#                      code.putln("PyThreadState *_save;")
+#                      code.putln("Py_UNBLOCK_THREADS")
+
+
+class GILExitNode(StatNode):
+    #  Used as the 'finally' block in a GILStatNode
+    #
+    #  state   string   'gil' or 'nogil'
+
+    def analyse_expressions(self, env):
+        pass
+
+    def generate_execution_code(self, code):
+        if self.state == 'gil':
+            code.putln("PyGILState_Release();")
+        else:
+            code.putln("Py_BLOCK_THREADS")
+
+
 class CImportStatNode(StatNode):
     #  cimport statement
     #
@@ -2406,7 +2587,7 @@ static int __Pyx_PrintItem(PyObject *v) {
         return -1;
     if (PyString_Check(v)) {
         char *s = PyString_AsString(v);
-        int len = PyString_Size(v);
+        Py_ssize_t len = PyString_Size(v);
         if (len > 0 &&
             isspace(Py_CHARMASK(s[len-1])) &&
             s[len-1] != ' ')
@@ -2454,21 +2635,12 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
         value = Py_None;
         Py_INCREF(value);
     }
-    /* Next, repeatedly, replace a tuple exception with its first item */
-    while (PyTuple_Check(type) && PyTuple_Size(type) > 0) {
-        PyObject *tmp = type;
-        type = PyTuple_GET_ITEM(type, 0);
-        Py_INCREF(type);
-        Py_DECREF(tmp);
-    }
-    if (PyString_Check(type)) {
-        if (PyErr_Warn(PyExc_DeprecationWarning,
-                "raising a string exception is deprecated"))
-            goto raise_error;
-    }
-    else if (PyType_Check(type) || PyClass_Check(type))
-        ; /*PyErr_NormalizeException(&type, &value, &tb);*/
-    else {
+    #if PY_VERSION_HEX < 0x02050000
+    if (!PyClass_Check(type))
+    #else
+    if (!PyType_Check(type))
+    #endif
+    {
         /* Raising an instance.  The value should be a dummy. */
         if (value != Py_None) {
             PyErr_SetString(PyExc_TypeError,
@@ -2478,11 +2650,25 @@ static void __Pyx_Raise(PyObject *type, PyObject *value, PyObject *tb) {
         /* Normalize to raise <class>, <instance> */
         Py_DECREF(value);
         value = type;
-        if (PyInstance_Check(type))
-            type = (PyObject*) ((PyInstanceObject*)type)->in_class;
-        else
+        #if PY_VERSION_HEX < 0x02050000
+            if (PyInstance_Check(type)) {
+                type = (PyObject*) ((PyInstanceObject*)type)->in_class;
+                Py_INCREF(type);
+            }
+            else {
+                PyErr_SetString(PyExc_TypeError,
+                    "raise: exception must be an old-style class or instance");
+                goto raise_error;
+            }
+        #else
             type = (PyObject*) type->ob_type;
-        Py_INCREF(type);
+            Py_INCREF(type);
+            if (!PyType_IsSubtype((PyTypeObject *)type, (PyTypeObject *)PyExc_BaseException)) {
+                PyErr_SetString(PyExc_TypeError,
+                    "raise: exception class must be a subclass of BaseException");
+                goto raise_error;
+            }
+        #endif
     }
     PyErr_Restore(type, value, tb);
     return;
@@ -2545,21 +2731,28 @@ static int __Pyx_ArgTypeTest(PyObject *obj, PyTypeObject *type, int none_allowed
 #  *kwds == 0, it is not changed. If kwds2 == 0 and *kwds != 0, a new
 #  reference to the same dictionary is passed back in *kwds.
 #
+#  If rqd_kwds is not 0, it is an array of booleans corresponding to the
+#  names in kwd_list, indicating required keyword arguments. If any of
+#  these are not present in kwds, an exception is raised.
+#
 
 get_starargs_utility_code = [
 """
-static int __Pyx_GetStarArgs(PyObject **args, PyObject **kwds,\
char *kwd_list[], int nargs, PyObject **args2, PyObject **kwds2); /*proto*/
+static int __Pyx_GetStarArgs(PyObject **args, PyObject **kwds, char *kwd_list[], \
   Py_ssize_t nargs, PyObject **args2, PyObject **kwds2, char rqd_kwds[]); /*proto*/
 ""","""
 static int __Pyx_GetStarArgs(
     PyObject **args, 
     PyObject **kwds,
     char *kwd_list[], 
-    int nargs,
+    Py_ssize_t nargs,
     PyObject **args2, 
-    PyObject **kwds2)
+    PyObject **kwds2,
+    char rqd_kwds[])
 {
     PyObject *x = 0, *args1 = 0, *kwds1 = 0;
+    int i;
+    char **p;
     
     if (args2)
         *args2 = 0;
@@ -2570,25 +2763,37 @@ static int __Pyx_GetStarArgs(
         args1 = PyTuple_GetSlice(*args, 0, nargs);
         if (!args1)
             goto bad;
-        *args2 = PyTuple_GetSlice(*args, nargs, PyTuple_Size(*args));
+        *args2 = PyTuple_GetSlice(*args, nargs, PyTuple_GET_SIZE(*args));
         if (!*args2)
             goto bad;
     }
+    else if (PyTuple_GET_SIZE(*args) > nargs) {
+        int m = nargs;
+        int n = PyTuple_GET_SIZE(*args);
+        PyErr_Format(PyExc_TypeError,
+            "function takes at most %d positional arguments (%d given)",
+                m, n);
+        goto bad;
+    }
     else {
         args1 = *args;
         Py_INCREF(args1);
     }
     
+    if (rqd_kwds && !*kwds)
+            for (i = 0, p = kwd_list; *p; i++, p++)
+                if (rqd_kwds[i])
+                    goto missing_kwarg;
+    
     if (kwds2) {
         if (*kwds) {
-            char **p;
             kwds1 = PyDict_New();
-            if (!kwds)
+            if (!kwds1)
                 goto bad;
             *kwds2 = PyDict_Copy(*kwds);
             if (!*kwds2)
                 goto bad;
-            for (p = kwd_list; *p; p++) {
+            for (i = 0, p = kwd_list; *p; i++, p++) {
                 x = PyDict_GetItemString(*kwds, *p);
                 if (x) {
                     if (PyDict_SetItemString(kwds1, *p, x) < 0)
@@ -2596,6 +2801,8 @@ static int __Pyx_GetStarArgs(
                     if (PyDict_DelItemString(*kwds2, *p) < 0)
                         goto bad;
                 }
+                else if (rqd_kwds && rqd_kwds[i])
+                    goto missing_kwarg;
             }
         }
         else {
@@ -2607,18 +2814,25 @@ static int __Pyx_GetStarArgs(
     else {
         kwds1 = *kwds;
         Py_XINCREF(kwds1);
+        if (rqd_kwds && *kwds)
+            for (i = 0, p = kwd_list; *p; i++, p++)
+                if (rqd_kwds[i] && !PyDict_GetItemString(*kwds, *p))
+                        goto missing_kwarg;
     }
     
     *args = args1;
     *kwds = kwds1;
     return 0;
+missing_kwarg:
+    PyErr_Format(PyExc_TypeError,
+        "required keyword argument '%s' is missing", *p);
 bad:
     Py_XDECREF(args1);
     Py_XDECREF(kwds1);
-    if (*args2) {
+    if (args2) {
         Py_XDECREF(*args2);
     }
-    if (*kwds2) {
+    if (kwds2) {
         Py_XDECREF(*kwds2);
     }
     return -1;
@@ -2714,63 +2928,6 @@ bad:
 
 #------------------------------------------------------------------------------------
 
-type_import_utility_code = [
-"""
-static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, long size);  /*proto*/
-""","""
-static PyTypeObject *__Pyx_ImportType(char *module_name, char *class_name, 
-    long size) 
-{
-    PyObject *py_module_name = 0;
-    PyObject *py_class_name = 0;
-    PyObject *py_name_list = 0;
-    PyObject *py_module = 0;
-    PyObject *result = 0;
-    
-    py_module_name = PyString_FromString(module_name);
-    if (!py_module_name)
-        goto bad;
-    py_class_name = PyString_FromString(class_name);
-    if (!py_class_name)
-        goto bad;
-    py_name_list = PyList_New(1);
-    if (!py_name_list)
-        goto bad;
-    Py_INCREF(py_class_name);
-    if (PyList_SetItem(py_name_list, 0, py_class_name) < 0)
-        goto bad;
-    py_module = __Pyx_Import(py_module_name, py_name_list);
-    if (!py_module)
-        goto bad;
-    result = PyObject_GetAttr(py_module, py_class_name);
-    if (!result)
-        goto bad;
-    if (!PyType_Check(result)) {
-        PyErr_Format(PyExc_TypeError, 
-            "%s.%s is not a type object",
-            module_name, class_name);
-        goto bad;
-    }
-    if (((PyTypeObject *)result)->tp_basicsize != size) {
-        PyErr_Format(PyExc_ValueError, 
-            "%s.%s does not appear to be the correct type object",
-            module_name, class_name);
-        goto bad;
-    }
-    goto done;
-bad:
-    Py_XDECREF(result);
-    result = 0;
-done:
-    Py_XDECREF(py_module_name);
-    Py_XDECREF(py_class_name);
-    Py_XDECREF(py_name_list);
-    return (PyTypeObject *)result;
-}
-"""]
-
-#------------------------------------------------------------------------------------
-
 set_vtable_utility_code = [
 """
 static int __Pyx_SetVtable(PyObject *dict, void *vtable); /*proto*/
@@ -2857,3 +3014,33 @@ static int __Pyx_InitStrings(__Pyx_StringTabEntry *t) {
 """]
 
 #------------------------------------------------------------------------------------
+
+get_exception_utility_code = [
+"""
+static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb); /*proto*/
+""","""
+static int __Pyx_GetException(PyObject **type, PyObject **value, PyObject **tb) {
+    PyThreadState *tstate = PyThreadState_Get();
+    PyErr_Fetch(type, value, tb);
+    PyErr_NormalizeException(type, value, tb);
+    if (PyErr_Occurred())
+        goto bad;
+    Py_INCREF(*type);
+    Py_INCREF(*value);
+    Py_INCREF(*tb);
+    Py_XDECREF(tstate->exc_type);
+    Py_XDECREF(tstate->exc_value);
+    Py_XDECREF(tstate->exc_traceback);
+    tstate->exc_type = *type;
+    tstate->exc_value = *value;
+    tstate->exc_traceback = *tb;
+    return 0;
+bad:
+    Py_XDECREF(*type);
+    Py_XDECREF(*value);
+    Py_XDECREF(*tb);
+    return -1;
+}
+"""]
+
+#------------------------------------------------------------------------------------
index 22bb490e10ea04ab7eff8dd4374fa01167e501d8..c767787e3c9e60f7941b2a48097e68c302317853 100644 (file)
@@ -441,13 +441,35 @@ def p_atom(s):
         if name == "None":
             return ExprNodes.NoneNode(pos)
         else:
-            return ExprNodes.NameNode(pos, name=name)
+            return p_name(s, name)
     elif sy == 'NULL':
         s.next()
         return ExprNodes.NullNode(pos)
     else:
         s.error("Expected an identifier or literal")
 
+def p_name(s, name):
+    pos = s.position()
+    if not s.compile_time_expr:
+        try:
+            value = s.compile_time_env.lookup_here(name)
+        except KeyError:
+            pass
+        else:
+            rep = repr(value)
+            if isinstance(value, int):
+                return ExprNodes.IntNode(pos, value = rep)
+            elif isinstance(value, long):
+                return ExprNodes.LongNode(pos, value = rep)
+            elif isinstance(value, float):
+                return ExprNodes.FloatNode(pos, value = rep)
+            elif isinstance(value, str):
+                return ExprNodes.StringNode(pos, value = rep[1:-1])
+            else:
+                error(pos, "Invalid type for compile-time constant: %s"
+                    % value.__class__.__name__)
+    return ExprNodes.NameNode(pos, name = name)
+
 def p_cat_string_literal(s):
     # A sequence of one or more adjacent string literals.
     # Returns (kind, value) where kind in ('', 'c', 'r')
@@ -645,7 +667,10 @@ def p_expression_or_assignment(s):
         expr_list.append(p_expr(s))
     if len(expr_list) == 1:
         expr = expr_list[0]
-        return Nodes.ExprStatNode(expr.pos, expr = expr)
+        if isinstance(expr, ExprNodes.StringNode):
+            return Nodes.PassStatNode(expr.pos)
+        else:
+            return Nodes.ExprStatNode(expr.pos, expr = expr)
     else:
         expr_list_list = []
         flatten_parallel_assignments(expr_list, expr_list_list)
@@ -769,10 +794,13 @@ def p_raise_statement(s):
             if s.sy == ',':
                 s.next()
                 exc_tb = p_simple_expr(s)
-    return Nodes.RaiseStatNode(pos, 
-        exc_type = exc_type,
-        exc_value = exc_value,
-        exc_tb = exc_tb)
+    if exc_type or exc_value or exc_tb:
+        return Nodes.RaiseStatNode(pos, 
+            exc_type = exc_type,
+            exc_value = exc_value,
+            exc_tb = exc_tb)
+    else:
+        return Nodes.ReraiseStatNode(pos)
 
 def p_import_statement(s):
     # s.sy in ('import', 'cimport')
@@ -790,13 +818,18 @@ def p_import_statement(s):
                 module_name = dotted_name,
                 as_name = as_name)
         else:
+            if as_name and "." in dotted_name:
+                name_list = ExprNodes.ListNode(pos, args = [
+                    ExprNodes.StringNode(pos, value = "*")])
+            else:
+                name_list = None
             stat = Nodes.SingleAssignmentNode(pos,
                 lhs = ExprNodes.NameNode(pos, 
                     name = as_name or target_name),
                 rhs = ExprNodes.ImportNode(pos, 
                     module_name = ExprNodes.StringNode(pos,
                         value = dotted_name),
-                    name_list = None))
+                    name_list = name_list))
         stats.append(stat)
     return Nodes.StatListNode(pos, stats = stats)
 
@@ -859,8 +892,6 @@ def p_dotted_name(s, as_allowed):
         names.append(p_ident(s))
     if as_allowed:
         as_name = p_as_name(s)
-    else:
-        as_name = None
     return (pos, target_name, join(names, "."), as_name)
 
 def p_as_name(s):
@@ -1039,17 +1070,32 @@ def p_include_statement(s, level):
     s.next() # 'include'
     _, include_file_name = p_string_literal(s)
     s.expect_newline("Syntax error in include statement")
-    include_file_path = s.context.find_include_file(include_file_name, pos)
-    if include_file_path:
-        f = open(include_file_path, "rU")
-        s2 = PyrexScanner(f, include_file_path, s)
-        try:
-            tree = p_statement_list(s2, level)
-        finally:
-            f.close()
-        return tree
+    if s.compile_time_eval:
+        include_file_path = s.context.find_include_file(include_file_name, pos)
+        if include_file_path:
+            f = open(include_file_path, "rU")
+            s2 = PyrexScanner(f, include_file_path, s)
+            try:
+                tree = p_statement_list(s2, level)
+            finally:
+                f.close()
+            return tree
+        else:
+            return None
     else:
-        return None
+        return Nodes.PassStatNode(pos)
+
+def p_with_statement(s):
+    pos = s.position()
+    s.next() # 'with'
+#      if s.sy == 'IDENT' and s.systring in ('gil', 'nogil'):
+    if s.sy == 'IDENT' and s.systring == 'nogil':
+        state = s.systring
+        s.next()
+        body = p_suite(s)
+        return Nodes.GILStatNode(pos, state = state, body = body)
+    else:
+        s.error(pos, "Only 'with gil' and 'with nogil' implemented")
     
 def p_simple_statement(s):
     #print "p_simple_statement:", s.sy, s.systring ###
@@ -1095,63 +1141,122 @@ def p_simple_statement_list(s):
     s.expect_newline("Syntax error in simple statement list")
     return stat
 
-def p_statement(s, level, cdef_flag = 0, visibility = 'private'):
-    #print "p_statement:", s.sy, s.systring ###
+def p_compile_time_expr(s):
+    old = s.compile_time_expr
+    s.compile_time_expr = 1
+    expr = p_expr(s)
+    s.compile_time_expr = old
+    return expr
+
+def p_DEF_statement(s):
+    pos = s.position()
+    denv = s.compile_time_env
+    s.next() # 'DEF'
+    name = p_ident(s)
+    s.expect('=')
+    expr = p_compile_time_expr(s)
+    value = expr.compile_time_value(denv)
+    #print "p_DEF_statement: %s = %r" % (name, value) ###
+    denv.declare(name, value)
+    s.expect_newline()
+    return Nodes.PassStatNode(pos)
+
+def p_IF_statement(s, level, cdef_flag, visibility, api):
+    pos = s.position
+    saved_eval = s.compile_time_eval
+    current_eval = saved_eval
+    denv = s.compile_time_env
+    result = None
+    while 1:
+        s.next() # 'IF' or 'ELIF'
+        expr = p_compile_time_expr(s)
+        s.compile_time_eval = current_eval and bool(expr.compile_time_value(denv))
+        body = p_suite(s, level, cdef_flag, visibility, api = api)
+        if s.compile_time_eval:
+            result = body
+            current_eval = 0
+        if s.sy <> 'ELIF':
+            break
+    if s.sy == 'ELSE':
+        s.next()
+        s.compile_time_eval = current_eval
+        body = p_suite(s, level, cdef_flag, visibility, api = api)
+        if current_eval:
+            result = body
+    if not result:
+        result = PassStatNode(pos)
+    s.compile_time_eval = saved_eval
+    return result
+
+def p_statement(s, level, cdef_flag = 0, visibility = 'private', api = 0):
     if s.sy == 'ctypedef':
         if level not in ('module', 'module_pxd'):
             s.error("ctypedef statement not allowed here")
+        if api:
+            error(s.pos, "'api' not allowed with 'ctypedef'")
         return p_ctypedef_statement(s, level, visibility)
-    if s.sy == 'cdef':
-        cdef_flag = 1
-        s.next()
-    if cdef_flag:
-        if level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_pxd'):
-            s.error('cdef statement not allowed here')
-        return p_cdef_statement(s, level, visibility)
-    elif s.sy == 'def':
-        if level not in ('module', 'class', 'c_class', 'property'):
-            s.error('def statement not allowed here')
-        return p_def_statement(s)
-    elif s.sy == 'class':
-        if level <> 'module':
-            s.error("class definition not allowed here")
-        return p_class_statement(s)
-    elif s.sy == 'include':
-        if level not in ('module', 'module_pxd'):
-            s.error("include statement not allowed here")
-        return p_include_statement(s, level)
-    elif level == 'c_class' and s.sy == 'IDENT' and s.systring == 'property':
-        return p_property_decl(s)
+    elif s.sy == 'DEF':
+        return p_DEF_statement(s)
+    elif s.sy == 'IF':
+        return p_IF_statement(s, level, cdef_flag, visibility, api)
     else:
-        if level in ('c_class', 'c_class_pxd'):
-            if s.sy == 'pass':
+        if s.sy == 'cdef':
+            cdef_flag = 1
+            s.next()
+        if cdef_flag:
+            if level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_pxd'):
+                s.error('cdef statement not allowed here')
+            return p_cdef_statement(s, level, visibility, api)
+        else:
+            if api:
+                error(s.pos, "'api' not allowed with this statement")
+            if s.sy == 'def':
+                if level not in ('module', 'class', 'c_class', 'property'):
+                    s.error('def statement not allowed here')
+                return p_def_statement(s)
+            elif s.sy == 'class':
+                if level <> 'module':
+                    s.error("class definition not allowed here")
+                return p_class_statement(s)
+            elif s.sy == 'include':
+                #if level not in ('module', 'module_pxd'):
+                #      s.error("include statement not allowed here")
+                return p_include_statement(s, level)
+            elif level == 'c_class' and s.sy == 'IDENT' and s.systring == 'property':
+                return p_property_decl(s)
+            elif s.sy == 'pass' and level <> 'property':
                 return p_pass_statement(s, with_newline = 1)
             else:
-                s.error("Executable statement not allowed here")
-        if s.sy == 'if':
-            return p_if_statement(s)
-        elif s.sy == 'while':
-            return p_while_statement(s)
-        elif s.sy == 'for':
-            return p_for_statement(s)
-        elif s.sy == 'try':
-            return p_try_statement(s)
-        else:
-            return p_simple_statement_list(s)
+                if level in ('c_class', 'c_class_pxd', 'property'):
+                    s.error("Executable statement not allowed here")
+                if s.sy == 'if':
+                    return p_if_statement(s)
+                elif s.sy == 'while':
+                    return p_while_statement(s)
+                elif s.sy == 'for':
+                    return p_for_statement(s)
+                elif s.sy == 'try':
+                    return p_try_statement(s)
+                elif s.sy == 'with':
+                    return p_with_statement(s)
+                else:
+                    return p_simple_statement_list(s)
 
 def p_statement_list(s, level,
-        cdef_flag = 0, visibility = 'private'):
+        cdef_flag = 0, visibility = 'private', api = 0):
     # Parse a series of statements separated by newlines.
-    #print "p_statement_list:", s.sy, s.systring ###
     pos = s.position()
     stats = []
     while s.sy not in ('DEDENT', 'EOF'):
         stats.append(p_statement(s, level,
-            cdef_flag = cdef_flag, visibility = visibility))
-    return Nodes.StatListNode(pos, stats = stats)
+            cdef_flag = cdef_flag, visibility = visibility, api = api))
+    if len(stats) == 1:
+        return stats[0]
+    else:
+        return Nodes.StatListNode(pos, stats = stats)
 
 def p_suite(s, level = 'other', cdef_flag = 0,
-        visibility = 'private', with_doc = 0):
+        visibility = 'private', with_doc = 0, with_pseudo_doc = 0, api = 0):
     pos = s.position()
     s.expect(':')
     doc = None
@@ -1159,14 +1264,17 @@ def p_suite(s, level = 'other', cdef_flag = 0,
     if s.sy == 'NEWLINE':
         s.next()
         s.expect_indent()
-        if with_doc:
+        if with_doc or with_pseudo_doc:
             doc = p_doc_string(s)
         body = p_statement_list(s, 
             level = level,
             cdef_flag = cdef_flag, 
-            visibility = visibility)
+            visibility = visibility,
+            api = api)
         s.expect_dedent()
     else:
+        if api:
+            error(s.pos, "'api' not allowed with this statement")
         if level in ('module', 'class', 'function', 'other'):
             body = p_simple_statement_list(s)
         else:
@@ -1185,6 +1293,16 @@ def p_c_base_type(s, self_flag = 0):
     else:
         return p_c_simple_base_type(s, self_flag)
 
+def p_calling_convention(s):
+    if s.sy == 'IDENT' and s.systring in calling_convention_words:
+        result = s.systring
+        s.next()
+        return result
+    else:
+        return ""
+
+calling_convention_words = ("__stdcall", "__cdecl")
+
 def p_c_complex_base_type(s):
     # s.sy == '('
     pos = s.position()
@@ -1200,13 +1318,11 @@ def p_c_simple_base_type(s, self_flag):
     is_basic = 0
     signed = 1
     longness = 0
-    pos = s.position()
     module_path = []
+    pos = s.position()
     if looking_at_base_type(s):
         #print "p_c_simple_base_type: looking_at_base_type at", s.position()
         is_basic = 1
-        #signed = p_signed_or_unsigned(s)
-        #longness = p_short_or_long(s)
         signed, longness = p_sign_and_longness(s)
         if s.sy == 'IDENT' and s.systring in basic_c_type_names:
             name = s.systring
@@ -1246,16 +1362,12 @@ def looking_at_dotted_name(s):
     else:
         return 0
 
-#base_type_start_words = (
-#      "char", "short", "int", "long", "float", "double",
-#      "void", "signed", "unsigned"
-#)
-
-basic_c_type_names = ("void", "char", "int", "float", "double")
+basic_c_type_names = ("void", "char", "int", "float", "double", "Py_ssize_t")
 
 sign_and_longness_words = ("short", "long", "signed", "unsigned")
 
-base_type_start_words = basic_c_type_names + sign_and_longness_words
+base_type_start_words = \
+    basic_c_type_names + sign_and_longness_words
 
 def p_sign_and_longness(s):
     signed = 1
@@ -1263,6 +1375,8 @@ def p_sign_and_longness(s):
     while s.sy == 'IDENT' and s.systring in sign_and_longness_words:
         if s.systring == 'unsigned':
             signed = 0
+        elif s.systring == 'signed':
+            signed = 2
         elif s.systring == 'short':
             longness = -1
         elif s.systring == 'long':
@@ -1270,27 +1384,6 @@ def p_sign_and_longness(s):
         s.next()
     return signed, longness
 
-#def p_signed_or_unsigned(s):
-#      signed = 1
-#      if s.sy == 'IDENT':
-#              if s.systring == 'signed':
-#                      s.next()
-#              elif s.systring == 'unsigned':
-#                      signed = 0
-#                      s.next()
-#      return signed
-#
-#def p_short_or_long(s):
-#      longness = 0
-#      if s.sy == 'IDENT' and s.systring == 'short':
-#              longness = -1
-#              s.next()
-#      else:
-#              while s.sy == 'IDENT' and s.systring == 'long':
-#                      longness += 1
-#                      s.next()
-#      return longness
-
 def p_opt_cname(s):
     literal = p_opt_string_literal(s)
     if literal:
@@ -1299,64 +1392,109 @@ def p_opt_cname(s):
         cname = None
     return cname
 
-def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0):
-    # If empty is true, the declarator must be
-    # empty, otherwise we don't care.
+def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0, nonempty = 0,
+        calling_convention_allowed = 0):
+    # If empty is true, the declarator must be empty. If nonempty is true,
+    # the declarator must be nonempty. Otherwise we don't care.
     # If cmethod_flag is true, then if this declarator declares
     # a function, it's a C method of an extension type.
     pos = s.position()
+    if s.sy == '(':
+        s.next()
+        if s.sy == ')' or looking_at_type(s):
+            base = Nodes.CNameDeclaratorNode(pos, name = "", cname = None)
+            result = p_c_func_declarator(s, pos, base, cmethod_flag)
+        else:
+            result = p_c_declarator(s, empty, is_type, cmethod_flag, nonempty,
+                calling_convention_allowed = 1)
+            s.expect(')')
+    else:
+        result = p_c_simple_declarator(s, empty, is_type, cmethod_flag, nonempty)
+    if not calling_convention_allowed and result.calling_convention and s.sy <> '(':
+        error(s.position(), "%s on something that is not a function"
+            % result.calling_convention)
+    while s.sy in ('[', '('):
+        pos = s.position()
+        if s.sy == '[':
+            result = p_c_array_declarator(s, result)
+        else: # sy == '('
+            s.next()
+            result = p_c_func_declarator(s, pos, result, cmethod_flag)
+        cmethod_flag = 0
+    return result
+
+def p_c_array_declarator(s, base):
+    pos = s.position()
+    s.next() # '['
+    if s.sy <> ']':
+        dim = p_expr(s)
+    else:
+        dim = None
+    s.expect(']')
+    return Nodes.CArrayDeclaratorNode(pos, base = base, dimension = dim)
+
+def p_c_func_declarator(s, pos, base, cmethod_flag):
+    #  Opening paren has already been skipped
+    args = p_c_arg_list(s, in_pyfunc = 0, cmethod_flag = cmethod_flag,
+        nonempty_declarators = 0)
+    ellipsis = p_optional_ellipsis(s)
+    s.expect(')')
+    nogil = p_nogil(s)
+    exc_val, exc_check = p_exception_value_clause(s)
+    with_gil = p_with_gil(s)
+    return Nodes.CFuncDeclaratorNode(pos, 
+        base = base, args = args, has_varargs = ellipsis,
+        exception_value = exc_val, exception_check = exc_check,
+        nogil = nogil or with_gil, with_gil = with_gil)
+
+def p_c_simple_declarator(s, empty, is_type, cmethod_flag, nonempty):
+    pos = s.position()
+    calling_convention = p_calling_convention(s)
     if s.sy == '*':
         s.next()
-        base = p_c_declarator(s, empty, is_type, cmethod_flag)
+        base = p_c_declarator(s, empty, is_type, cmethod_flag, nonempty)
         result = Nodes.CPtrDeclaratorNode(pos, 
             base = base)
     elif s.sy == '**': # scanner returns this as a single token
         s.next()
-        base = p_c_declarator(s, empty, is_type, cmethod_flag)
+        base = p_c_declarator(s, empty, is_type, cmethod_flag, nonempty)
         result = Nodes.CPtrDeclaratorNode(pos,
             base = Nodes.CPtrDeclaratorNode(pos,
                 base = base))
     else:
-        if s.sy == '(':
+        if s.sy == 'IDENT':
+            name = s.systring
+            if is_type:
+                s.add_type_name(name)
+            if empty:
+                error(s.position(), "Declarator should be empty")
             s.next()
-            result = p_c_declarator(s, empty, is_type, cmethod_flag)
-            s.expect(')')
+            cname = p_opt_cname(s)
         else:
-            if s.sy == 'IDENT':
-                name = s.systring
-                if is_type:
-                    s.add_type_name(name)
-                if empty:
-                    error(s.position(), "Declarator should be empty")
-                s.next()
-                cname = p_opt_cname(s)
-            else:
-                name = ""
-                cname = None
-            result = Nodes.CNameDeclaratorNode(pos,
-                name = name, cname = cname)
-        while s.sy in ('[', '('):
-            if s.sy == '[':
-                s.next()
-                if s.sy <> ']':
-                    dim = p_expr(s)
-                else:
-                    dim = None
-                s.expect(']')
-                result = Nodes.CArrayDeclaratorNode(pos, 
-                    base = result, dimension = dim)
-            else: # sy == '('
-                s.next()
-                args = p_c_arg_list(s, in_pyfunc = 0, cmethod_flag = cmethod_flag)
-                ellipsis = p_optional_ellipsis(s)
-                s.expect(')')
-                exc_val, exc_check = p_exception_value_clause(s)
-                result = Nodes.CFuncDeclaratorNode(pos, 
-                    base = result, args = args, has_varargs = ellipsis,
-                    exception_value = exc_val, exception_check = exc_check)
-            cmethod_flag = 0
+            if nonempty:
+                error(s.position(), "Empty declarator")
+            name = ""
+            cname = None
+        result = Nodes.CNameDeclaratorNode(pos,
+            name = name, cname = cname)
+    result.calling_convention = calling_convention
     return result
 
+def p_nogil(s):
+    if s.sy == 'IDENT' and s.systring == 'nogil':
+        s.next()
+        return 1
+    else:
+        return 0
+
+def p_with_gil(s):
+    if s.sy == 'with':
+        s.next()
+        s.expect_keyword('gil')
+        return 1
+    else:
+        return 0
+
 def p_exception_value_clause(s):
     exc_val = None
     exc_check = 0
@@ -1369,32 +1507,38 @@ def p_exception_value_clause(s):
             if s.sy == '?':
                 exc_check = 1
                 s.next()
-            exc_val = p_simple_expr(s) #p_exception_value(s)
+            exc_val = p_simple_expr(s)
     return exc_val, exc_check
 
-#def p_exception_value(s):
-#      sign = ""
-#      if s.sy == "-":
-#              sign = "-"
-#              s.next()
-#      if s.sy in ('INT', 'LONG', 'FLOAT', 'NULL'):
-#              s.systring = sign + s.systring
-#              return p_atom(s)
-#      else:
-#              s.error("Exception value must be an int or float literal or NULL")
-
 c_arg_list_terminators = ('*', '**', '.', ')')
-c_arg_list_trailers = ('.', '*', '**')
 
-def p_c_arg_list(s, in_pyfunc, cmethod_flag = 0):
+#def p_c_arg_list(s, in_pyfunc, cmethod_flag = 0, nonempty_declarators = 0,
+#              kw_only = 0):
+#      args = []
+#      if s.sy not in c_arg_list_terminators:
+#              args.append(p_c_arg_decl(s, in_pyfunc, cmethod_flag,
+#                      nonempty = nonempty_declarators, kw_only = kw_only))
+#              while s.sy == ',':
+#                      s.next()
+#                      if s.sy in c_arg_list_terminators:
+#                              break
+#                      args.append(p_c_arg_decl(s, in_pyfunc), nonempty = nonempty_declarators,
+#                              kw_only = kw_only)
+#      return args
+
+def p_c_arg_list(s, in_pyfunc, cmethod_flag = 0, nonempty_declarators = 0,
+        kw_only = 0):
+    #  Comma-separated list of C argument declarations, possibly empty.
+    #  May have a trailing comma.
     args = []
-    if s.sy not in c_arg_list_terminators:
-        args.append(p_c_arg_decl(s, in_pyfunc, cmethod_flag))
-        while s.sy == ',':
-            s.next()
-            if s.sy in c_arg_list_trailers:
-                break
-            args.append(p_c_arg_decl(s, in_pyfunc))
+    is_self_arg = cmethod_flag
+    while s.sy not in c_arg_list_terminators:
+        args.append(p_c_arg_decl(s, in_pyfunc, is_self_arg,
+            nonempty = nonempty_declarators, kw_only = kw_only))
+        if s.sy <> ',':
+            break
+        s.next()
+        is_self_arg = 0
     return args
 
 def p_optional_ellipsis(s):
@@ -1404,12 +1548,12 @@ def p_optional_ellipsis(s):
     else:
         return 0
 
-def p_c_arg_decl(s, in_pyfunc, cmethod_flag = 0):
+def p_c_arg_decl(s, in_pyfunc, cmethod_flag = 0, nonempty = 0, kw_only = 0):
     pos = s.position()
     not_none = 0
     default = None
     base_type = p_c_base_type(s, cmethod_flag)
-    declarator = p_c_declarator(s)
+    declarator = p_c_declarator(s, nonempty = nonempty)
     if s.sy == 'not':
         s.next()
         if s.sy == 'IDENT' and s.systring == 'None':
@@ -1426,32 +1570,54 @@ def p_c_arg_decl(s, in_pyfunc, cmethod_flag = 0):
         base_type = base_type,
         declarator = declarator,
         not_none = not_none,
-        default = default)
+        default = default,
+        kw_only = kw_only)
+
+def p_api(s):
+    if s.sy == 'IDENT' and s.systring == 'api':
+        s.next()
+        return 1
+    else:
+        return 0
 
-def p_cdef_statement(s, level, visibility = 'private'):
+def p_cdef_statement(s, level, visibility = 'private', api = 0):
     pos = s.position()
     visibility = p_visibility(s, visibility)
-    if visibility == 'extern' and s.sy in ('from' ,':'):
+    api = api or p_api(s)
+    if api:
+        if visibility not in ('private', 'public'):
+            error(pos, "Cannot combine 'api' with '%s'" % visibility)
+    if visibility == 'extern' and s.sy == 'from':
             return p_cdef_extern_block(s, level, pos)
+    elif s.sy == ':':
+        p_cdef_block(s, level, visibility, api)
     elif s.sy == 'class':
         if level not in ('module', 'module_pxd'):
             error(pos, "Extension type definition not allowed here")
+        if api:
+            error(pos, "'api' not allowed with extension class")
         return p_c_class_definition(s, level, pos, visibility = visibility)
     elif s.sy == 'IDENT' and s.systring in struct_union_or_enum:
         if level not in ('module', 'module_pxd'):
             error(pos, "C struct/union/enum definition not allowed here")
-        if visibility == 'public':
-            error(pos, "Public struct/union/enum definition not implemented")
+        #if visibility == 'public':
+        #      error(pos, "Public struct/union/enum definition not implemented")
+        if api:
+            error(pos, "'api' not allowed with '%s'" % s.systring)
         if s.systring == "enum":
-            return p_c_enum_definition(s, pos)
+            return p_c_enum_definition(s, pos, visibility)
         else:
-            return p_c_struct_or_union_definition(s, pos)
+            return p_c_struct_or_union_definition(s, pos, visibility)
     elif s.sy == 'pass':
         node = p_pass_statement(s)
         s.expect_newline('Expected a newline')
         return node
     else:
-        return p_c_func_or_var_declaration(s, level, pos, visibility)
+        return p_c_func_or_var_declaration(s, level, pos, visibility, api)
+
+def p_cdef_block(s, level, visibility, api):
+    body = p_suite(s, level, cdef_flag = 1, visibility = 'extern', api = api)
+    return Nodes.StatListNode(pos, stats = body)
 
 def p_cdef_extern_block(s, level, pos):
     include_file = None
@@ -1469,7 +1635,7 @@ struct_union_or_enum = (
     "struct", "union", "enum"
 )
 
-def p_c_enum_definition(s, pos, typedef_flag = 0):
+def p_c_enum_definition(s, pos, visibility, typedef_flag = 0):
     # s.sy == ident 'enum'
     s.next()
     if s.sy == 'IDENT':
@@ -1492,7 +1658,7 @@ def p_c_enum_definition(s, pos, typedef_flag = 0):
             p_c_enum_line(s, items)
         s.expect_dedent()
     return Nodes.CEnumDefNode(pos, name = name, cname = cname,
-        items = items, typedef_flag = typedef_flag)
+        items = items, typedef_flag = typedef_flag, visibility = visibility)
 
 def p_c_enum_line(s, items):
     if s.sy <> 'pass':
@@ -1517,7 +1683,7 @@ def p_c_enum_item(s, items):
     items.append(Nodes.CEnumDefItemNode(pos, 
         name = name, cname = cname, value = value))
 
-def p_c_struct_or_union_definition(s, pos, typedef_flag = 0):
+def p_c_struct_or_union_definition(s, pos, visibility, typedef_flag = 0):
     # s.sy == ident 'struct' or 'union'
     kind = s.systring
     s.next()
@@ -1542,7 +1708,7 @@ def p_c_struct_or_union_definition(s, pos, typedef_flag = 0):
         s.expect_newline("Syntax error in struct or union definition")
     return Nodes.CStructOrUnionDefNode(pos, 
         name = name, cname = cname, kind = kind, attributes = attributes,
-        typedef_flag = typedef_flag)
+        typedef_flag = typedef_flag, visibility = visibility)
 
 def p_visibility(s, prev_visibility):
     pos = s.position()
@@ -1555,35 +1721,36 @@ def p_visibility(s, prev_visibility):
         s.next()
     return visibility
 
-def p_c_func_or_var_declaration(s, level, pos, visibility = 'private'):
+def p_c_func_or_var_declaration(s, level, pos, visibility = 'private', api = 0):
     cmethod_flag = level in ('c_class', 'c_class_pxd')
     base_type = p_c_base_type(s)
-    declarator = p_c_declarator(s, cmethod_flag = cmethod_flag)
+    declarator = p_c_declarator(s, cmethod_flag = cmethod_flag, nonempty = 1)
     if s.sy == ':':
         if level not in ('module', 'c_class'):
             s.error("C function definition not allowed here")
-        suite = p_suite(s, 'function')
+        suite = p_suite(s, 'function', with_pseudo_doc = 1)
         result = Nodes.CFuncDefNode(pos,
             visibility = visibility,
             base_type = base_type,
             declarator = declarator, 
-            body = suite)
+            body = suite,
+            api = api)
     else:
-        if level == 'module_pxd' and visibility <> 'extern':
-            error(pos, 
-                "Only 'extern' C function or variable declaration allowed in .pxd file")
+        if api:
+            error(s.pos, "'api' not allowed with variable declaration")
         declarators = [declarator]
         while s.sy == ',':
             s.next()
             if s.sy == 'NEWLINE':
                 break
-            declarator = p_c_declarator(s, cmethod_flag = cmethod_flag)
+            declarator = p_c_declarator(s, cmethod_flag = cmethod_flag, nonempty = 1)
             declarators.append(declarator)
         s.expect_newline("Syntax error in C variable declaration")
         result = Nodes.CVarDefNode(pos, 
             visibility = visibility,
             base_type = base_type, 
-            declarators = declarators)
+            declarators = declarators,
+            in_pxd = level == 'module_pxd')
     return result
 
 def p_ctypedef_statement(s, level, visibility = 'private'):
@@ -1597,38 +1764,42 @@ def p_ctypedef_statement(s, level, visibility = 'private'):
             typedef_flag = 1)
     elif s.sy == 'IDENT' and s.systring in ('struct', 'union', 'enum'):
         if s.systring == 'enum':
-            return p_c_enum_definition(s, pos, typedef_flag = 1)
+            return p_c_enum_definition(s, pos, visibility, typedef_flag = 1)
         else:
-            return p_c_struct_or_union_definition(s, pos, typedef_flag = 1)
+            return p_c_struct_or_union_definition(s, pos, visibility, typedef_flag = 1)
     else:
         base_type = p_c_base_type(s)
-        declarator = p_c_declarator(s, is_type = 1)
+        declarator = p_c_declarator(s, is_type = 1, nonempty = 1)
         s.expect_newline("Syntax error in ctypedef statement")
         return Nodes.CTypeDefNode(pos,
-            base_type = base_type, declarator = declarator)
+            base_type = base_type, declarator = declarator, visibility = visibility)
 
 def p_def_statement(s):
     # s.sy == 'def'
     pos = s.position()
     s.next()
     name = p_ident(s)
-    args = []
+    #args = []
     s.expect('(');
-    args = p_c_arg_list(s, in_pyfunc = 1)
+    args = p_c_arg_list(s, in_pyfunc = 1, nonempty_declarators = 1)
     star_arg = None
     starstar_arg = None
     if s.sy == '*':
         s.next()
-        star_arg = p_py_arg_decl(s)
+        if s.sy == 'IDENT':
+            star_arg = p_py_arg_decl(s)
         if s.sy == ',':
             s.next()
-            if s.sy == '**':
-                s.next()
-                starstar_arg = p_py_arg_decl(s)
-    elif s.sy == '**':
+            args.extend(p_c_arg_list(s, in_pyfunc = 1,
+                nonempty_declarators = 1, kw_only = 1))
+        elif s.sy <>')':
+            s.error("Syntax error in Python function argument list")
+    if s.sy == '**':
         s.next()
         starstar_arg = p_py_arg_decl(s)
     s.expect(')')
+    if p_nogil(s):
+        error(s.pos, "Python function cannot be declared nogil")
     doc, body = p_suite(s, 'function', with_doc = 1)
     return Nodes.DefNode(pos, name = name, args = args, 
         star_arg = star_arg, starstar_arg = starstar_arg,
index e0e359470001331ec7e8cc77bf0f019a4b544990..0944a489eb4955c87687344f65dd25c2739029ab 100644 (file)
@@ -5,7 +5,21 @@
 import string
 import Naming
 
-class PyrexType:
+class BaseType:
+    #
+    #  Base class for all Pyrex types including pseudo-types.
+
+    def cast_code(self, expr_code):
+        return "((%s)%s)" % (self.declaration_code(""), expr_code)
+    
+    def base_declaration_code(self, base_code, entity_code):
+        if entity_code:
+            return "%s %s" % (base_code, entity_code)
+        else:
+            return base_code
+
+
+class PyrexType(BaseType):
     #
     #  Base class for all Pyrex types.
     #
@@ -21,6 +35,7 @@ class PyrexType:
     #  is_cfunction          boolean     Is a C function type
     #  is_struct_or_union    boolean     Is a C struct or union type
     #  is_enum               boolean     Is a C enum type
+    #  is_typedef            boolean     Is a typedef type
     #  is_string             boolean     Is a C char * type
     #  is_returncode         boolean     Is used only to signal exceptions
     #  is_error              boolean     Is the dummy error type
@@ -66,6 +81,7 @@ class PyrexType:
     is_cfunction = 0
     is_struct_or_union = 0
     is_enum = 0
+    is_typedef = 0
     is_string = 0
     is_returncode = 0
     is_error = 0
@@ -111,17 +127,20 @@ class PyrexType:
         # A type is incomplete if it is an unsized array,
         # a struct whose attributes are not defined, etc.
         return 1
-    
-    def cast_code(self, expr_code):
-        return "((%s)%s)" % (self.declaration_code(""), expr_code)
 
 
-class CTypedefType:
+class CTypedefType(BaseType):
     #
-    #  Type defined with a ctypedef statement in a
+    #  Pseudo-type defined with a ctypedef statement in a
     #  'cdef extern from' block. Delegates most attribute
-    #  lookups to the base type.
+    #  lookups to the base type. ANYTHING NOT DEFINED
+    #  HERE IS DELEGATED!
     #
+    #  qualified_name      string
+    #  typedef_cname       string
+    #  typedef_base_type   PyrexType
+    
+    is_typedef = 1
     
     def __init__(self, cname, base_type):
         self.typedef_cname = cname
@@ -132,10 +151,23 @@ class CTypedefType:
     
     def declaration_code(self, entity_code, 
             for_display = 0, dll_linkage = None, pyrex = 0):
-        return "%s %s" % (self.typedef_cname, entity_code)
+        name = self.declaration_name(for_display, pyrex)
+        return self.base_declaration_code(name, entity_code)
+    
+    def declaration_name(self, for_display = 0, pyrex = 0):
+        if pyrex or for_display:
+            return self.qualified_name
+        else:
+            return self.typedef_cname
+    
+    def as_argument_type(self):
+        return self
+
+    def __repr__(self):
+        return "<CTypedefType %s>" % self.typedef_cname
     
     def __str__(self):
-        return self.typedef_cname
+        return self.declaration_name(for_display = 1)
     
     def __getattr__(self, name):
         return getattr(self.typedef_base_type, name)
@@ -155,15 +187,15 @@ class PyObjectType(PyrexType):
         return "Python object"
     
     def __repr__(self):
-        return "PyObjectType"
+        return "<PyObjectType>"
     
     def assignable_from(self, src_type):
         return 1 # Conversion will be attempted
         
     def declaration_code(self, entity_code, 
             for_display = 0, dll_linkage = None, pyrex = 0):
-        if pyrex:
-            return "object %s" % entity_code
+        if pyrex or for_display:
+            return self.base_declaration_code("object", entity_code)
         else:
             return "%s *%s" % (public_decl("PyObject", dll_linkage), entity_code)
 
@@ -226,8 +258,8 @@ class PyExtensionType(PyObjectType):
     
     def declaration_code(self, entity_code, 
             for_display = 0, dll_linkage = None, pyrex = 0):
-        if pyrex:
-            return "%s %s" % (self.name, entity_code)
+        if pyrex or for_display:
+            return self.base_declaration_code(self.name, entity_code)
         else:
             if self.typedef_flag:
                 base_format = "%s"
@@ -243,8 +275,8 @@ class PyExtensionType(PyObjectType):
         return self.name
     
     def __repr__(self):
-        return "PyExtensionType(%s%s)" % (self.scope.class_name,
-            ("", ".typedef_flag=1")[self.typedef_flag])
+        return "<PyExtensionType %s%s>" % (self.scope.class_name,
+            ("", " typedef")[self.typedef_flag])
     
 
 class CType(PyrexType):
@@ -259,13 +291,6 @@ class CType(PyrexType):
     from_py_function = None
 
 
-#class CSimpleType(CType):
-#      #
-#      #  Base class for all unstructured C types.
-#      #
-#      pass
-
-
 class CVoidType(CType):
     is_void = 1
     
@@ -275,7 +300,7 @@ class CVoidType(CType):
     def declaration_code(self, entity_code, 
             for_display = 0, dll_linkage = None, pyrex = 0):
         base = public_decl("void", dll_linkage)
-        return "%s %s" % (base, entity_code)
+        return self.base_declaration_code(base, entity_code)
     
     def is_complete(self):
         return 0
@@ -286,17 +311,20 @@ class CNumericType(CType):
     #   Base class for all C numeric types.
     #
     #   rank      integer     Relative size
-    #   signed    boolean
+    #   signed    integer     0 = unsigned, 1 = unspecified, 2 = explicitly signed
     #
     
     is_numeric = 1
     default_value = "0"
     
     parsetuple_formats = ( # rank -> format
-        "?HIkK???", # unsigned
-        "chilLfd?", # signed
+        "BHIkK????", # unsigned
+        "bhilL?fd?", # assumed signed
+        "bhilL?fd?", # explicitly signed
     )
     
+    sign_words = ("unsigned ", "", "signed ")
+    
     def __init__(self, rank, signed = 1, pymemberdef_typecode = None):
         self.rank = rank
         self.signed = signed
@@ -306,21 +334,18 @@ class CNumericType(CType):
         self.parsetuple_format = ptf
         self.pymemberdef_typecode = pymemberdef_typecode
     
+    def sign_and_name(self):
+        s = self.sign_words[self.signed]
+        n = rank_to_type_name[self.rank]
+        return s + n
+    
     def __repr__(self):
-        if self.signed:
-            u = ""
-        else:
-            u = "unsigned "
-        return "<CNumericType %s%s>" % (u, rank_to_type_name[self.rank])
+        return "<CNumericType %s>" % self.sign_and_name()
     
     def declaration_code(self, entity_code, 
             for_display = 0, dll_linkage = None, pyrex = 0):
-        if self.signed:
-            u = ""
-        else:
-            u = "unsigned "
-        base = public_decl(u + rank_to_type_name[self.rank], dll_linkage)
-        return "%s %s" % (base,  entity_code)
+        base = public_decl(self.sign_and_name(), dll_linkage)
+        return self.base_declaration_code(base,  entity_code)
     
 
 class CIntType(CNumericType):
@@ -338,6 +363,11 @@ class CIntType(CNumericType):
         return src_type.is_int or src_type.is_enum or src_type is error_type
 
 
+class CAnonEnumType(CIntType):
+
+    is_enum = 1        
+
+
 class CUIntType(CIntType):
 
     to_py_function = "PyLong_FromUnsignedLong"
@@ -362,6 +392,12 @@ class CULongLongType(CIntType):
     from_py_function = "PyInt_AsUnsignedLongLongMask"
 
 
+class CPySSizeTType(CIntType):
+
+    to_py_function = "PyInt_FromSsize_t"
+    from_py_function = "PyInt_AsSsize_t"
+
+
 class CFloatType(CNumericType):
 
     is_float = 1
@@ -388,7 +424,7 @@ class CArrayType(CType):
             self.is_string = 1
     
     def __repr__(self):
-        return "CArrayType(%s,%s)" % (self.size, repr(self.base_type))
+        return "<CArrayType %s %s>" % (self.size, repr(self.base_type))
     
     def same_as_resolved_type(self, other_type):
         return ((other_type.is_array and
@@ -408,8 +444,10 @@ class CArrayType(CType):
             dimension_code = self.size
         else:
             dimension_code = ""
+        if entity_code.startswith("*"):
+            entity_code = "(%s)" % entity_code
         return self.base_type.declaration_code(
-            "(%s[%s])" % (entity_code, dimension_code),
+            "%s[%s]" % (entity_code, dimension_code),
             for_display, dll_linkage, pyrex)
     
     def as_argument_type(self):
@@ -423,13 +461,13 @@ class CPtrType(CType):
     #  base_type     CType    Referenced type
     
     is_ptr = 1
-    default_value = 0
+    default_value = "0"
     
     def __init__(self, base_type):
         self.base_type = base_type
     
     def __repr__(self):
-        return "CPtrType(%s)" % repr(self.base_type)
+        return "<CPtrType %s>" % repr(self.base_type)
     
     def same_as_resolved_type(self, other_type):
         return ((other_type.is_ptr and
@@ -440,24 +478,20 @@ class CPtrType(CType):
             for_display = 0, dll_linkage = None, pyrex = 0):
         #print "CPtrType.declaration_code: pointer to", self.base_type ###
         return self.base_type.declaration_code(
-            "(*%s)" % entity_code,
+            "*%s" % entity_code,
             for_display, dll_linkage, pyrex)
     
     def assignable_from_resolved_type(self, other_type):
         if other_type is error_type:
             return 1
-        elif self.base_type.is_cfunction and other_type.is_cfunction:
-            return self.base_type.same_as(other_type)
-        elif other_type.is_array:
-            return self.base_type.same_as(other_type.base_type)
-        elif not other_type.is_ptr:
-            return 0
-        elif self.base_type.is_void:
-            return 1
         elif other_type.is_null_ptr:
             return 1
+        elif self.base_type.is_cfunction and other_type.is_cfunction:
+            return self.base_type.same_as(other_type)
+        elif other_type.is_array or other_type.is_ptr:
+            return self.base_type.is_void or self.base_type.same_as(other_type.base_type)
         else:
-            return self.base_type.same_as(other_type.base_type)
+            return 0
 
 
 class CNullPtrType(CPtrType):
@@ -470,31 +504,48 @@ class CFuncType(CType):
     #  args             [CFuncTypeArg]
     #  has_varargs      boolean
     #  exception_value  string
-    #  exception_check  boolean  True if PyErr_Occurred check needed
+    #  exception_check  boolean    True if PyErr_Occurred check needed
+    #  calling_convention  string  Function calling convention
+    #  nogil            boolean    Can be called without gil
+    #  with_gil         boolean    Acquire gil around function body
     
     is_cfunction = 1
     
-    def __init__(self, return_type, args, has_varargs,
-            exception_value = None, exception_check = 0):
+    def __init__(self, return_type, args, has_varargs = 0,
+            exception_value = None, exception_check = 0, calling_convention = "",
+            nogil = 0, with_gil = 0):
         self.return_type = return_type
         self.args = args
         self.has_varargs = has_varargs
         self.exception_value = exception_value
         self.exception_check = exception_check
+        self.calling_convention = calling_convention
+        self.nogil = nogil
+        self.with_gil = with_gil
     
     def __repr__(self):
         arg_reprs = map(repr, self.args)
         if self.has_varargs:
             arg_reprs.append("...")
-        return "CFuncType(%s,[%s])" % (
+        return "<CFuncType %s %s[%s]>" % (
             repr(self.return_type),
+            self.calling_convention_prefix(),
             string.join(arg_reprs, ","))
     
+    def calling_convention_prefix(self):
+        cc = self.calling_convention
+        if cc:
+            return cc + " "
+        else:
+            return ""
+    
     def same_c_signature_as(self, other_type, as_cmethod = 0):
         return self.same_c_signature_as_resolved_type(
             other_type.resolve(), as_cmethod)
 
     def same_c_signature_as_resolved_type(self, other_type, as_cmethod):
+        #print "CFuncType.same_c_signature_as_resolved_type:", \
+        #      self, other_type, "as_cmethod =", as_cmethod ###
         if other_type is error_type:
             return 1
         if not other_type.is_cfunction:
@@ -513,8 +564,15 @@ class CFuncType(CType):
             return 0
         if not self.return_type.same_as(other_type.return_type):
             return 0
+        if not self.same_calling_convention_as(other_type):
+            return 0
         return 1
     
+    def same_calling_convention_as(self, other):
+        sc1 = self.calling_convention == '__stdcall'
+        sc2 = other.calling_convention == '__stdcall'
+        return sc1 == sc2
+    
     def same_exception_signature_as(self, other_type):
         return self.same_exception_signature_as_resolved_type(
             other_type.resolve())
@@ -539,17 +597,25 @@ class CFuncType(CType):
         if not arg_decl_code and not pyrex:
             arg_decl_code = "void"
         exc_clause = ""
-        if pyrex or for_display:
+        if (pyrex or for_display) and not self.return_type.is_pyobject:
             if self.exception_value and self.exception_check:
                 exc_clause = " except? %s" % self.exception_value
             elif self.exception_value:
                 exc_clause = " except %s" % self.exception_value
             elif self.exception_check:
                 exc_clause = " except *"
+        cc = self.calling_convention_prefix()
+        if (not entity_code and cc) or entity_code.startswith("*"):
+            entity_code = "(%s%s)" % (cc, entity_code)
+            cc = ""
         return self.return_type.declaration_code(
-            "(%s(%s)%s)" % (entity_code, arg_decl_code, exc_clause),
+            "%s%s(%s)%s" % (cc, entity_code, arg_decl_code, exc_clause),
             for_display, dll_linkage, pyrex)
 
+    def signature_string(self):
+        s = self.declaration_code("")
+        return s
+
 
 class CFuncTypeArg:
     #  name       string
@@ -588,13 +654,13 @@ class CStructOrUnionType(CType):
         self.typedef_flag = typedef_flag
         
     def __repr__(self):
-        return "CStructOrUnionType(%s,%s%s)" % (self.name, self.cname,
-            ("", ",typedef_flag=1")[self.typedef_flag])
+        return "<CStructOrUnionType %s %s%s>" % (self.name, self.cname,
+            ("", " typedef")[self.typedef_flag])
 
     def declaration_code(self, entity_code, 
             for_display = 0, dll_linkage = None, pyrex = 0):
         if pyrex:
-            return "%s %s" % (self.name, entity_code)
+            return self.base_declaration_code(self.name, entity_code)
         else:
             if for_display:
                 base = self.name
@@ -602,7 +668,7 @@ class CStructOrUnionType(CType):
                 base = self.cname
             else:
                 base = "%s %s" % (self.kind, self.cname)
-            return "%s %s" % (public_decl(base, dll_linkage), entity_code)
+            return self.base_declaration_code(public_decl(base, dll_linkage), entity_code)
 
     def is_complete(self):
         return self.scope is not None
@@ -617,8 +683,8 @@ class CEnumType(CType):
     #  typedef_flag   boolean
     
     is_enum = 1
-    #signed = 1
-    #rank = 2
+    signed = 1
+    rank = -1 # Ranks below any integer type
     to_py_function = "PyInt_FromLong"
     from_py_function = "PyInt_AsLong"
 
@@ -628,20 +694,23 @@ class CEnumType(CType):
         self.values = []
         self.typedef_flag = typedef_flag
     
+    def __str__(self):
+        return self.name
+    
     def __repr__(self):
-        return "CEnumType(%s,%s%s)" % (self.name, self.cname,
-            ("", ",typedef_flag=1")[self.typedef_flag])
+        return "<CEnumType %s %s%s>" % (self.name, self.cname,
+            ("", " typedef")[self.typedef_flag])
     
     def declaration_code(self, entity_code, 
             for_display = 0, dll_linkage = None, pyrex = 0):
         if pyrex:
-            return "%s %s" % (self.cname, entity_code)
+            return self.base_declaration_code(self.cname, entity_code)
         else:
             if self.typedef_flag:
                 base = self.cname
             else:
                 base = "enum %s" % self.cname
-            return "%s %s" % (public_decl(base, dll_linkage), entity_code)
+            return self.base_declaration_code(public_decl(base, dll_linkage), entity_code)
 
 
 class CStringType:
@@ -699,21 +768,28 @@ c_void_type =         CVoidType()
 c_void_ptr_type =     CPtrType(c_void_type)
 c_void_ptr_ptr_type = CPtrType(c_void_ptr_type)
 
-c_char_type =     CIntType(0, 1, "T_CHAR")
-c_short_type =    CIntType(1, 1, "T_SHORT")
-c_int_type =      CIntType(2, 1, "T_INT")
-c_long_type =     CIntType(3, 1, "T_LONG")
-c_longlong_type = CLongLongType(4, 1, "T_LONGLONG")
-
-c_uchar_type =     CIntType(0, 0, "T_UBYTE")
-c_ushort_type =    CIntType(1, 0, "T_USHORT")
-c_uint_type =      CUIntType(2, 0, "T_UINT")
-c_ulong_type =     CULongType(3, 0, "T_ULONG")
-c_ulonglong_type = CULongLongType(4, 0, "T_ULONGLONG")
-
-c_float_type =      CFloatType(5, "T_FLOAT")
-c_double_type =     CFloatType(6, "T_DOUBLE")
-c_longdouble_type = CFloatType(7)
+c_uchar_type =       CIntType(0, 0, "T_UBYTE")
+c_ushort_type =      CIntType(1, 0, "T_USHORT")
+c_uint_type =        CUIntType(2, 0, "T_UINT")
+c_ulong_type =       CULongType(3, 0, "T_ULONG")
+c_ulonglong_type =   CULongLongType(4, 0, "T_ULONGLONG")
+
+c_char_type =        CIntType(0, 1, "T_CHAR")
+c_short_type =       CIntType(1, 1, "T_SHORT")
+c_int_type =         CIntType(2, 1, "T_INT")
+c_long_type =        CIntType(3, 1, "T_LONG")
+c_longlong_type =    CLongLongType(4, 1, "T_LONGLONG")
+c_py_ssize_t_type =  CPySSizeTType(5, 1)
+
+c_schar_type =       CIntType(0, 2, "T_CHAR")
+c_sshort_type =      CIntType(1, 2, "T_SHORT")
+c_sint_type =        CIntType(2, 2, "T_INT")
+c_slong_type =       CIntType(3, 2, "T_LONG")
+c_slonglong_type =   CLongLongType(4, 2, "T_LONGLONG")
+
+c_float_type =       CFloatType(6, "T_FLOAT")
+c_double_type =      CFloatType(7, "T_DOUBLE")
+c_longdouble_type =  CFloatType(8)
 
 c_null_ptr_type =     CNullPtrType(c_void_type)
 c_char_array_type =   CCharArrayType(None)
@@ -723,9 +799,11 @@ c_int_ptr_type =      CPtrType(c_int_type)
 
 c_returncode_type =   CIntType(2, 1, "T_INT", is_returncode = 1)
 
+c_anon_enum_type =    CAnonEnumType(-1, 1)
+
 error_type =    ErrorType()
 
-lowest_float_rank = 5
+lowest_float_rank = 6
 
 rank_to_type_name = (
     "char",         # 0
@@ -733,9 +811,10 @@ rank_to_type_name = (
     "int",          # 2
     "long",         # 3
     "PY_LONG_LONG", # 4
-    "float",        # 5
-    "double",       # 6
-    "long double",  # 7
+    "Py_ssize_t",   # 5
+    "float",        # 6
+    "double",       # 7
+    "long double",  # 8
 )
 
 sign_and_rank_to_type = {
@@ -750,9 +829,16 @@ sign_and_rank_to_type = {
     (1, 2): c_int_type, 
     (1, 3): c_long_type,
     (1, 4): c_longlong_type,
-    (1, 5): c_float_type, 
-    (1, 6): c_double_type,
-    (1, 7): c_longdouble_type,
+    (1, 5): c_py_ssize_t_type,
+    (2, 0): c_schar_type, 
+    (2, 1): c_sshort_type, 
+    (2, 2): c_sint_type, 
+    (2, 3): c_slong_type,
+    (2, 4): c_slonglong_type,
+    (2, 5): c_py_ssize_t_type,
+    (1, 6): c_float_type, 
+    (1, 7): c_double_type,
+    (1, 8): c_longdouble_type,
 }
 
 modifiers_and_name_to_type = {
@@ -768,20 +854,29 @@ modifiers_and_name_to_type = {
     (1, 0, "int"): c_int_type, 
     (1, 1, "int"): c_long_type,
     (1, 2, "int"): c_longlong_type,
+    (1, 0, "Py_ssize_t"): c_py_ssize_t_type,
     (1, 0, "float"): c_float_type, 
     (1, 0, "double"): c_double_type,
     (1, 1, "double"): c_longdouble_type,
     (1, 0, "object"): py_object_type,
+    (2, 0, "char"): c_schar_type, 
+    (2, -1, "int"): c_sshort_type, 
+    (2, 0, "int"): c_sint_type, 
+    (2, 1, "int"): c_slong_type,
+    (2, 2, "int"): c_slonglong_type,
+    (2, 0, "Py_ssize_t"): c_py_ssize_t_type,
 }
 
 def widest_numeric_type(type1, type2):
     # Given two numeric types, return the narrowest type
     # encompassing both of them.
-    signed = type1.signed
-    rank = max(type1.rank, type2.rank)
-    if rank >= lowest_float_rank:
-        signed = 1
-    return sign_and_rank_to_type[signed, rank]
+    if type1.is_enum and type2.is_enum:
+        widest_type = c_int_type
+    elif type2.rank > type1.rank:
+        widest_type = type2
+    else:
+        widest_type = type1
+    return widest_type
 
 def simple_c_type(signed, longness, name):
     # Find type descriptor for simple type given name and modifiers.
index 26ce042bb7391b304534778c7f6ededf2651dee4..d620419743514d027ef22fe18958c5caa9a9f587 100644 (file)
@@ -6,6 +6,7 @@
 import cPickle as pickle
 
 import os
+import platform
 import stat
 import sys
 from time import time
@@ -138,7 +139,7 @@ reserved_words = [
     "raise", "import", "exec", "try", "except", "finally",
     "while", "if", "elif", "else", "for", "in", "assert",
     "and", "or", "not", "is", "in", "lambda", "from",
-    "NULL", "cimport"
+    "NULL", "cimport", "with", "DEF", "IF", "ELIF", "ELSE"
 ]
 
 class Method:
@@ -160,7 +161,53 @@ def build_resword_dict():
 
 #------------------------------------------------------------------
 
+class CompileTimeScope(object):
+
+    def __init__(self, outer = None):
+        self.entries = {}
+        self.outer = outer
+    
+    def declare(self, name, value):
+        self.entries[name] = value
+    
+    def lookup_here(self, name):
+        return self.entries[name]
+    
+    def lookup(self, name):
+        try:
+            return self.lookup_here(name)
+        except KeyError:
+            outer = self.outer
+            if outer:
+                return outer.lookup(name)
+            else:
+                raise
+
+def initial_compile_time_env():
+    benv = CompileTimeScope()
+    names = ('UNAME_SYSNAME', 'UNAME_NODENAME', 'UNAME_RELEASE',
+        'UNAME_VERSION', 'UNAME_MACHINE')
+    for name, value in zip(names, platform.uname()):
+        benv.declare(name, value)
+    import __builtin__
+    names = ('False', 'True',
+        'abs', 'bool', 'chr', 'cmp', 'complex', 'dict', 'divmod', 'enumerate',
+        'float', 'hash', 'hex', 'int', 'len', 'list', 'long', 'map', 'max', 'min',
+        'oct', 'ord', 'pow', 'range', 'reduce', 'repr', 'round', 'slice', 'str',
+        'sum', 'tuple', 'xrange', 'zip')
+    for name in names:
+        benv.declare(name, getattr(__builtin__, name))
+    denv = CompileTimeScope(benv)
+    return denv
+
+#------------------------------------------------------------------
+
 class PyrexScanner(Scanner):
+    #  context            Context  Compilation context
+    #  type_names         set      Identifiers to be treated as type names
+    #  compile_time_env   dict     Environment for conditional compilation
+    #  compile_time_eval  boolean  In a true conditional compilation context
+    #  compile_time_expr  boolean  In a compile-time expression context
     
     resword_dict = build_resword_dict()
 
@@ -170,9 +217,15 @@ class PyrexScanner(Scanner):
         if parent_scanner:
             self.context = parent_scanner.context
             self.type_names = parent_scanner.type_names
+            self.compile_time_env = parent_scanner.compile_time_env
+            self.compile_time_eval = parent_scanner.compile_time_eval
+            self.compile_time_expr = parent_scanner.compile_time_expr
         else:
             self.context = context
             self.type_names = type_names
+            self.compile_time_env = initial_compile_time_env()
+            self.compile_time_eval = 1
+            self.compile_time_expr = 0
         self.trace = trace_scanner
         self.indentation_stack = [0]
         self.indentation_char = None
@@ -303,10 +356,19 @@ class PyrexScanner(Scanner):
         if self.sy == what:
             self.next()
         else:
-            if message:
-                self.error(message)
-            else:
-                self.error("Expected '%s'" % what)
+            self.expected(what, message)
+    
+    def expect_keyword(self, what, message = None):
+        if self.sy == 'IDENT' and self.systring == what:
+            self.next()
+        else:
+            self.expected(what, message)
+    
+    def expected(self, what, message):
+        if message:
+            self.error(message)
+        else:
+            self.error("Expected '%s'" % what)
         
     def expect_indent(self):
         self.expect('INDENT',
@@ -316,7 +378,7 @@ class PyrexScanner(Scanner):
         self.expect('DEDENT',
             "Expected a decrease in indentation level")
 
-    def expect_newline(self, message):
+    def expect_newline(self, message = "Expected a newline"):
         # Expect either a newline or end of file
         if self.sy <> 'EOF':
             self.expect('NEWLINE', message)
index 3ac9218c9a7f8e5894d9b37a5dcd61db3e9ac58e..765451eae9c95e9ac8a79bf5855563fa32e96fa0 100644 (file)
@@ -3,9 +3,10 @@
 #
 
 import re
-from Errors import error, InternalError
+from Errors import warning, error, InternalError
 import Options
 import Naming
+import PyrexTypes
 from PyrexTypes import c_int_type, \
     py_object_type, c_char_array_type, \
     CEnumType, CStructOrUnionType, PyExtensionType
@@ -24,7 +25,7 @@ class Entry:
     # doc              string     Doc string
     # init             string     Initial value
     # visibility       'private' or 'public' or 'extern'
-    # is_builtin       boolean    Is a Python builtin name
+    # is_builtin       boolean    Is an entry in the Python builtins dict
     # is_cglobal       boolean    Is a C global variable
     # is_pyglobal      boolean    Is a Python module-level variable
     #                               or class attribute during
@@ -48,7 +49,7 @@ class Entry:
     # signature        Signature  Arg & return types for Python func
     # init_to_none     boolean    True if initial value should be None
     # as_variable      Entry      Alternative interpretation of extension
-    #                               type name as a variable
+    #                               type name or builtin C function as a variable
     # xdecref_cleanup  boolean    Use Py_XDECREF for error cleanup
     # in_cinclude      boolean    Suppress C declaration code
     # enum_values      [Entry]    For enum types, list of values
@@ -58,10 +59,14 @@ class Entry:
     #                                 type is an extension type
     # as_module        None       Module scope, if a cimported module
     # is_inherited     boolean    Is an inherited attribute of an extension type
-    # interned_cname   string     C name of interned name string
+    # #interned_cname   string     C name of interned name string
     # pystring_cname   string     C name of Python version of string literal
     # is_interned      boolean    For string const entries, value is interned
     # used             boolean
+    # is_special       boolean    Is a special method or property accessor
+    #                               of an extension type
+    # defined_in_pxd   boolean    Is defined in a .pxd file (not just declared)
+    # api              boolean    Generate C API for C function
 
     borrowed = 0
     init = ""
@@ -89,11 +94,14 @@ class Entry:
     in_cinclude = 0
     as_module = None
     is_inherited = 0
-    interned_cname = None
+    #interned_cname = None
     pystring_cname = None
     is_interned = 0
     used = 0
-    
+    is_special = 0
+    defined_in_pxd = 0
+    api = 0
+
     def __init__(self, name, cname, type, pos = None, init = None):
         self.name = name
         self.cname = cname
@@ -107,6 +115,7 @@ class Scope:
     # outer_scope       Scope or None      Enclosing scope
     # entries           {string : Entry}   Python name to entry, non-types
     # const_entries     [Entry]            Constant entries
+    # type_entries      [Entry]            Struct/union/enum/typedef/exttype entries
     # sue_entries       [Entry]            Struct/union/enum entries
     # arg_entries       [Entry]            Function argument entries
     # var_entries       [Entry]            User-defined variable entries
@@ -148,6 +157,7 @@ class Scope:
             self.scope_prefix = mangled_name
         self.entries = {}
         self.const_entries = []
+        self.type_entries = []
         self.sue_entries = []
         self.arg_entries = []
         self.var_entries = []
@@ -221,27 +231,41 @@ class Scope:
         return entry
     
     def declare_type(self, name, type, pos, 
-            cname = None, visibility = 'private'):
+            cname = None, visibility = 'private', defining = 1):
         # Add an entry for a type definition.
         if not cname:
             cname = name
         entry = self.declare(name, cname, type, pos)
         entry.visibility = visibility
         entry.is_type = 1
+        if defining:
+            self.type_entries.append(entry)
         return entry
+    
+    def declare_typedef(self, name, base_type, pos, cname = None,
+            visibility = 'private'):
+        if not cname:
+            if self.in_cinclude or visibility == 'public':
+                cname = name
+            else:
+                cname = self.mangle(Naming.type_prefix, name)
+        type = PyrexTypes.CTypedefType(cname, base_type)
+        entry = self.declare_type(name, type, pos, cname, visibility)
+        type.qualified_name = entry.qualified_name
         
     def declare_struct_or_union(self, name, kind, scope, 
-            typedef_flag, pos, cname = None):
+            typedef_flag, pos, cname = None, visibility = 'private'):
         # Add an entry for a struct or union definition.
         if not cname:
-            if self.in_cinclude:
+            if self.in_cinclude or visibility == 'public':
                 cname = name
             else:
                 cname = self.mangle(Naming.type_prefix, name)
         entry = self.lookup_here(name)
         if not entry:
             type = CStructOrUnionType(name, kind, scope, typedef_flag, cname)
-            entry = self.declare_type(name, type, pos, cname)
+            entry = self.declare_type(name, type, pos, cname,
+                visibility = visibility, defining = scope is not None)
             self.sue_entries.append(entry)
         else:
             if not (entry.is_type and entry.type.is_struct_or_union):
@@ -250,8 +274,10 @@ class Scope:
                 error(pos, "'%s' already defined" % name)
             else:
                 self.check_previous_typedef_flag(entry, typedef_flag, pos)
+                self.check_previous_visibility(entry, visibility, pos)
                 if scope:
                     entry.type.scope = scope
+                    self.type_entries.append(entry)
         if not scope and not entry.type.scope:
             self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
         return entry
@@ -261,17 +287,24 @@ class Scope:
             error(pos, "'%s' previously declared using '%s'" % (
                 entry.name, ("cdef", "ctypedef")[entry.type.typedef_flag]))
     
-    def declare_enum(self, name, pos, cname, typedef_flag):
+    def check_previous_visibility(self, entry, visibility, pos):
+        if entry.visibility <> visibility:
+            error(pos, "'%s' previously declared as '%s'" % (
+                entry.name, entry.visibility))
+    
+    def declare_enum(self, name, pos, cname, typedef_flag,
+            visibility = 'private'):
         if name:
             if not cname:
-                if self.in_cinclude:
+                if self.in_cinclude or visibility == 'public':
                     cname = name
                 else:
                     cname = self.mangle(Naming.type_prefix, name)
             type = CEnumType(name, cname, typedef_flag)
         else:
-            type = c_int_type
-        entry = self.declare_type(name, type, pos, cname = cname)
+            type = PyrexTypes.c_anon_enum_type
+        entry = self.declare_type(name, type, pos, cname = cname,
+            visibility = visibility)
         entry.enum_values = []
         self.sue_entries.append(entry)
         return entry   
@@ -303,15 +336,26 @@ class Scope:
         self.pyfunc_entries.append(entry)
     
     def declare_cfunction(self, name, type, pos, 
-            cname = None, visibility = 'private', defining = 0):
+            cname = None, visibility = 'private', defining = 0, api = 0, in_pxd = 0):
         # Add an entry for a C function.
-        if not cname:
-            if visibility <> 'private':
-                cname = name
-            else:
-                cname = self.mangle(Naming.func_prefix, name)
-        entry = self.add_cfunction(name, type, pos, cname, visibility)
-        entry.func_cname = cname
+        entry = self.lookup_here(name)
+        if entry:
+            if not entry.type.same_as(type):
+                error(pos, "Function signature does not match previous declaration")
+        else:
+            if not cname:
+                if api or visibility <> 'private':
+                    cname = name
+                else:
+                    cname = self.mangle(Naming.func_prefix, name)
+            entry = self.add_cfunction(name, type, pos, cname, visibility)
+            entry.func_cname = cname
+        if in_pxd and visibility <> 'extern':
+            entry.defined_in_pxd = 1
+        if api:
+            entry.api = 1
+        if not defining and not in_pxd and visibility <> 'extern':
+            error(pos, "Non-extern C function declared but not defined")
         return entry
     
     def add_cfunction(self, name, type, pos, cname, visibility):
@@ -457,6 +501,15 @@ class BuiltinScope(Scope):
         entry.is_builtin = 1
         return entry
     
+    def declare_builtin_cfunction(self, name, type, cname, with_python_equiv = 0):
+        entry = self.declare_cfunction(name, type, None, cname)
+        if with_python_equiv:
+            var_entry = Entry(name, name, py_object_type)
+            var_entry.is_variable = 1
+            var_entry.is_builtin = 1
+            entry.as_variable = var_entry
+        return entry
+
 
 class ModuleScope(Scope):
     # module_name          string             Python name of the module
@@ -515,7 +568,7 @@ class ModuleScope(Scope):
     
     def declare_builtin(self, name, pos):
         entry = Scope.declare_builtin(self, name, pos)
-        entry.interned_cname = self.intern(name)
+        #entry.interned_cname = self.intern(name)
         return entry
     
     def intern(self, name):
@@ -598,8 +651,8 @@ class ModuleScope(Scope):
                     "Non-cdef global variable is not a generic Python object")
             entry.is_pyglobal = 1
             entry.namespace_cname = self.module_cname
-            if Options.intern_names:
-                entry.interned_cname = self.intern(name)
+            #if Options.intern_names:
+            #  entry.interned_cname = self.intern(name)
         else:
             entry.is_cglobal = 1
             self.var_entries.append(entry)
@@ -636,9 +689,6 @@ class ModuleScope(Scope):
         module_name, base_type, objstruct_cname, typeobj_cname,
         visibility, typedef_flag):
         #
-        #print "declare_c_class:", name
-        #print "...visibility =", visibility
-        #
         # Look for previous declaration as a type
         #
         entry = self.lookup_here(name)
@@ -660,7 +710,8 @@ class ModuleScope(Scope):
             else:
                 type.module_name = self.qualified_name
             type.typeptr_cname = self.mangle(Naming.typeptr_prefix, name)
-            entry = self.declare_type(name, type, pos, visibility = visibility)
+            entry = self.declare_type(name, type, pos, visibility = visibility,
+                defining = 0)
             if objstruct_cname:
                 type.objstruct_cname = objstruct_cname
             elif not entry.in_cinclude:
@@ -680,6 +731,7 @@ class ModuleScope(Scope):
                 if base_type:
                     scope.declare_inherited_c_attributes(base_type.scope)
                 type.set_scope(scope)
+                self.type_entries.append(entry)
             else:
                 self.check_for_illegal_incomplete_ctypedef(typedef_flag, pos)
         else:
@@ -690,11 +742,13 @@ class ModuleScope(Scope):
         #
         # Fill in options, checking for compatibility with any previous declaration
         #
+        if defining:
+            entry.defined_in_pxd = 1
         if implementing:   # So that filenames in runtime exceptions refer to
             entry.pos = pos  # the .pyx file and not the .pxd file
         if entry.visibility <> visibility:
             error(pos, "Declaration of '%s' as '%s' conflicts with previous "
-                "declaration as '%s'" % (class_name, visibility, entry.visibility))
+                "declaration as '%s'" % (name, visibility, entry.visibility))
         if objstruct_cname:
             if type.objstruct_cname and type.objstruct_cname <> objstruct_cname:
                 error(pos, "Object struct name differs from previous declaration")
@@ -884,8 +938,8 @@ class PyClassScope(ClassScope):
             cname, visibility, is_cdef)
         entry.is_pyglobal = 1
         entry.namespace_cname = self.class_obj_cname
-        if Options.intern_names:
-            entry.interned_cname = self.intern(name)
+        #if Options.intern_names:
+        #      entry.interned_cname = self.intern(name)
         return entry
 
     def allocate_temp(self, type):
@@ -976,18 +1030,28 @@ class CClassScope(ClassScope):
 
     def declare_pyfunction(self, name, pos):
         # Add an entry for a method.
+        if name == "__new__":
+            warning(pos, "__new__ method of extension type will change semantics "
+                "in a future version of Pyrex. Use __cinit__ instead.")
+            name = "__cinit__"
         entry = self.declare(name, name, py_object_type, pos)
         special_sig = get_special_method_signature(name)
         if special_sig:
+            entry.is_special = 1
             entry.signature = special_sig
             # Special methods don't get put in the method table
         else:
             entry.signature = pymethod_signature
             self.pyfunc_entries.append(entry)
         return entry
-            
+    
+    def lookup_here(self, name):
+        if name == "__new__":
+            name = "__cinit__"
+        return ClassScope.lookup_here(self, name)
+    
     def declare_cfunction(self, name, type, pos,
-            cname = None, visibility = 'private', defining = 0):
+            cname = None, visibility = 'private', defining = 0, api = 0, in_pxd = 0):
         if get_special_method_signature(name):
             error(pos, "Special methods must be declared with 'def', not 'cdef'")
         args = type.args
@@ -1002,6 +1066,7 @@ class CClassScope(ClassScope):
             else:
                 if defining and entry.func_cname:
                     error(pos, "'%s' already defined" % name)
+                #print "CClassScope.declare_cfunction: checking signature" ###
                 if not entry.type.same_as(type, as_cmethod = 1):
                     error(pos, "Signature does not match previous declaration")
         else:
@@ -1059,6 +1124,7 @@ class PropertyScope(Scope):
         signature = get_property_accessor_signature(name)
         if signature:
             entry = self.declare(name, name, py_object_type, pos)
+            entry.is_special = 1
             entry.signature = signature
             return entry
         else:
index c173710a1acc966445d2859f97b22f9b320106b4..28cb056b9c82e46dcac63560909136c5fade2ae7 100644 (file)
@@ -26,6 +26,7 @@ class Signature:
     #    'i'  int
     #    'I'  int *
     #    'l'  long
+    #    'Z'  Py_ssize_t
     #    's'  char *
     #    'S'  char **
     #    'r'  int used only to signal exception
@@ -42,6 +43,7 @@ class Signature:
         'i': PyrexTypes.c_int_type,
         'I': PyrexTypes.c_int_ptr_type,
         'l': PyrexTypes.c_long_type,
+        'Z': PyrexTypes.c_py_ssize_t_type,
         's': PyrexTypes.c_char_ptr_type,
         'S': PyrexTypes.c_char_ptr_ptr_type,
         'r': PyrexTypes.c_returncode_type,
@@ -80,6 +82,19 @@ class Signature:
     
     def return_type(self):
         return self.format_map[self.ret_format]
+    
+    def exception_value(self):
+        return self.error_value_map.get(self.ret_format)
+    
+    def function_type(self):
+        #  Construct a C function type descriptor for this signature
+        args = []
+        for i in xrange(self.num_fixed_args()):
+            arg_type = self.fixed_arg_type(i)
+            args.append(PyrexTypes.CFuncTypeArg("", arg_type, None))
+        ret_type = self.return_type()
+        exc_value = self.exception_value()
+        return PyrexTypes.CFuncType(ret_type, args, exception_value = exc_value)
 
 
 class SlotDescriptor:
@@ -87,17 +102,24 @@ class SlotDescriptor:
     #
     #  slot_name    string           Member name of the slot in the type object
     #  is_initialised_dynamically    Is initialised by code in the module init function
-
-    def __init__(self, slot_name, dynamic = 0):
+    #  flag                          Py_TPFLAGS_XXX value indicating presence of slot
+    
+    def __init__(self, slot_name, dynamic = 0, flag = None):
         self.slot_name = slot_name
         self.is_initialised_dynamically = dynamic
+        self.flag = flag
     
     def generate(self, scope, code):
         if self.is_initialised_dynamically:
             value = 0
         else:
             value = self.slot_code(scope)
+        flag = self.flag
+        if flag:
+            code.putln("#if Py_TPFLAGS_DEFAULT & %s" % flag)
         code.putln("%s, /*%s*/" % (value, self.slot_name))
+        if flag:
+            code.putln("#endif")
     
     # Some C implementations have trouble statically 
     # initialising a global with a pointer to an extern 
@@ -159,8 +181,8 @@ class MethodSlot(SlotDescriptor):
     #  method_name  string           The __xxx__ name of the method
     #  default      string or None   Default value of the slot
     
-    def __init__(self, signature, slot_name, method_name, default = None):
-        SlotDescriptor.__init__(self, slot_name)
+    def __init__(self, signature, slot_name, method_name, default = None, flag = None):
+        SlotDescriptor.__init__(self, slot_name, flag = flag)
         self.signature = signature
         self.slot_name = slot_name
         self.method_name = method_name
@@ -354,18 +376,28 @@ ternaryfunc = Signature("OOO", "O")        # typedef PyObject * (*ternaryfunc)(P
 iternaryfunc = Signature("TOO", "O")       # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
 callfunc = Signature("T*", "O")            # typedef PyObject * (*ternaryfunc)(PyObject *, PyObject *, PyObject *);
 inquiry = Signature("T", "i")              # typedef int (*inquiry)(PyObject *);
+lenfunc = Signature("T", "Z")              # typedef Py_ssize_t (*lenfunc)(PyObject *);
                                            # typedef int (*coercion)(PyObject **, PyObject **);
 intargfunc = Signature("Ti", "O")          # typedef PyObject *(*intargfunc)(PyObject *, int);
+ssizeargfunc = Signature("TZ", "O")        # typedef PyObject *(*ssizeargfunc)(PyObject *, Py_ssize_t);
 intintargfunc = Signature("Tii", "O")      # typedef PyObject *(*intintargfunc)(PyObject *, int, int);
+ssizessizeargfunc = Signature("TZZ", "O")  # typedef PyObject *(*ssizessizeargfunc)(PyObject *, Py_ssize_t, Py_ssize_t);
 intobjargproc = Signature("TiO", 'r')      # typedef int(*intobjargproc)(PyObject *, int, PyObject *);
+ssizeobjargproc = Signature("TZO", 'r')    # typedef int(*ssizeobjargproc)(PyObject *, Py_ssize_t, PyObject *);
 intintobjargproc = Signature("TiiO", 'r')  # typedef int(*intintobjargproc)(PyObject *, int, int, PyObject *);
+ssizessizeobjargproc = Signature("TZZO", 'r') # typedef int(*ssizessizeobjargproc)(PyObject *, Py_ssize_t, Py_ssize_t, PyObject *);
 intintargproc = Signature("Tii", 'r')
+ssizessizeargproc = Signature("TZZ", 'r')
 objargfunc = Signature("TO", "O")
 objobjargproc = Signature("TOO", 'r')      # typedef int (*objobjargproc)(PyObject *, PyObject *, PyObject *);
 getreadbufferproc = Signature("TiP", 'i')  # typedef int (*getreadbufferproc)(PyObject *, int, void **);
 getwritebufferproc = Signature("TiP", 'i') # typedef int (*getwritebufferproc)(PyObject *, int, void **);
 getsegcountproc = Signature("TI", 'i')     # typedef int (*getsegcountproc)(PyObject *, int *);
 getcharbufferproc = Signature("TiS", 'i')  # typedef int (*getcharbufferproc)(PyObject *, int, const char **);
+readbufferproc = Signature("TZP", "Z")     # typedef Py_ssize_t (*readbufferproc)(PyObject *, Py_ssize_t, void **);
+writebufferproc = Signature("TZP", "Z")    # typedef Py_ssize_t (*writebufferproc)(PyObject *, Py_ssize_t, void **);
+segcountproc = Signature("TZ", "Z")        # typedef Py_ssize_t (*segcountproc)(PyObject *, Py_ssize_t *);
+writebufferproc = Signature("TZS", "Z")        # typedef Py_ssize_t (*charbufferproc)(PyObject *, Py_ssize_t, char **);
 objargproc = Signature("TO", 'r')          # typedef int (*objobjproc)(PyObject *, PyObject *);
                                            # typedef int (*visitproc)(PyObject *, void *);
                                            # typedef int (*traverseproc)(PyObject *, visitproc, void *);
@@ -454,14 +486,15 @@ PyNumberMethods = (
     MethodSlot(binaryfunc, "nb_true_divide", "__truediv__"),
     MethodSlot(ibinaryfunc, "nb_inplace_floor_divide", "__ifloordiv__"),
     MethodSlot(ibinaryfunc, "nb_inplace_true_divide", "__itruediv__"),
+    MethodSlot(unaryfunc, "nb_index", "__index__", flag = "Py_TPFLAGS_HAVE_INDEX")
 )
 
 PySequenceMethods = (
-    MethodSlot(inquiry, "sq_length", "__len__"),    # EmptySlot("sq_length"), # mp_length used instead
+    MethodSlot(lenfunc, "sq_length", "__len__"),
     EmptySlot("sq_concat"), # nb_add used instead
     EmptySlot("sq_repeat"), # nb_multiply used instead
     SyntheticSlot("sq_item", ["__getitem__"], "0"),    #EmptySlot("sq_item"),   # mp_subscript used instead
-    MethodSlot(intintargfunc, "sq_slice", "__getslice__"),
+    MethodSlot(ssizessizeargfunc, "sq_slice", "__getslice__"),
     EmptySlot("sq_ass_item"), # mp_ass_subscript used instead
     SyntheticSlot("sq_ass_slice", ["__setslice__", "__delslice__"], "0"),
     MethodSlot(cmpfunc, "sq_contains", "__contains__"),
@@ -470,7 +503,7 @@ PySequenceMethods = (
 )
 
 PyMappingMethods = (
-    MethodSlot(inquiry, "mp_length", "__len__"),
+    MethodSlot(lenfunc, "mp_length", "__len__"),
     MethodSlot(objargfunc, "mp_subscript", "__getitem__"),
     SyntheticSlot("mp_ass_subscript", ["__setitem__", "__delitem__"], "0"),
 )
@@ -561,12 +594,12 @@ slot_table = (
 #
 #------------------------------------------------------------------------------------------
 
-MethodSlot(initproc, "", "__new__")
+MethodSlot(initproc, "", "__cinit__")
 MethodSlot(destructor, "", "__dealloc__")
 MethodSlot(objobjargproc, "", "__setitem__")
 MethodSlot(objargproc, "", "__delitem__")
-MethodSlot(intintobjargproc, "", "__setslice__")
-MethodSlot(intintargproc, "", "__delslice__")
+MethodSlot(ssizessizeobjargproc, "", "__setslice__")
+MethodSlot(ssizessizeargproc, "", "__delslice__")
 MethodSlot(getattrofunc, "", "__getattr__")
 MethodSlot(setattrofunc, "", "__setattr__")
 MethodSlot(delattrofunc, "", "__delattr__")
index be15e839073b9159e84a4a04bb8eee672b060f47..95e6fa3d6b9628444546aa15650b31dc244cb820 100644 (file)
@@ -1 +1 @@
-version = '0.9.5.1a'
+version = '0.9.6.2'
index 3c538b6425512928fefea2d116f8247e6d9109bc..1fbccd885fb6def74b8b7e16e07a8f57fb650f64 100644 (file)
@@ -7,7 +7,7 @@
 def print_call_chain(*args):
     import sys
     print " ".join(map(str, args))
-    f = sys._getframe(2)
+    f = sys._getframe(1)
     while f:
         name = f.f_code.co_name
         s = f.f_locals.get('self', None)
index 5033ac0492fac3503e81980297da076952358767..49493bf2fb9a7a3049c99710ef81af5054ee3d4c 100644 (file)
@@ -1,22 +1,11 @@
 # July 2002, Graham Fawcett
-
 #
-
 # this hack was inspired by the way Thomas Heller got py2exe
-
 # to appear as a distutil command
-
 #
-
 # we replace distutils.command.build_ext with our own version
-
 # and keep the old one under the module name _build_ext,
-
 # so that *our* build_ext can make use of it.
 
-
-
 from build_ext import build_ext
-
-
-
+from extension import Extension
index 95c0a745d897c4e113c4e9f14d31c51398e410c8..ae7758b2137a3cb899023a19859deec1d4bdedbb 100644 (file)
-# Subclasses disutils.command.build_ext,
-# replacing it with a Pyrex version that compiles pyx->c
-# before calling the original build_ext command.
-# July 2002, Graham Fawcett
-# Modified by Darrell Gallion <dgallion1@yahoo.com>
-# to allow inclusion of .c files along with .pyx files.
-# Pyrex is (c) Greg Ewing.
+"""Pyrex.Distutils.build_ext
 
-import distutils.command.build_ext
-#import Pyrex.Compiler.Main
-from Pyrex.Compiler.Main import CompilationOptions, default_options, compile
-from Pyrex.Compiler.Errors import PyrexError
-from distutils.dep_util import newer
-import os
-import sys
+Implements a version of the Distutils 'build_ext' command, for
+building Pyrex extension modules."""
 
-def replace_suffix(path, new_suffix):
-    return os.path.splitext(path)[0] + new_suffix
+# This module should be kept compatible with Python 2.1.
 
-class build_ext (distutils.command.build_ext.build_ext):
+__revision__ = "$Id:$"
 
-    description = "compile Pyrex scripts, then build C/C++ extensions (compile/link to build directory)"
+import sys, os, string, re
+from types import *
+from distutils.core import Command
+from distutils.errors import *
+from distutils.sysconfig import customize_compiler, get_python_version
+from distutils.dep_util import newer_group
+from distutils import log
+from distutils.dir_util import mkpath
+try:
+    from Pyrex.Compiler.Main \
+        import CompilationOptions, \
+               default_options as pyrex_default_options, \
+               compile as pyrex_compile
+    from Pyrex.Compiler.Errors import PyrexError
+except ImportError:
+    PyrexError = None
+
+from distutils.command import build_ext as _build_ext
+
+extension_name_re = _build_ext.extension_name_re
+
+show_compilers = _build_ext.show_compilers
+
+class build_ext(_build_ext.build_ext):
+
+    description = "build C/C++ and Pyrex extensions (compile/link to build directory)"
+
+    sep_by = _build_ext.build_ext.sep_by
+    user_options = _build_ext.build_ext.user_options
+    boolean_options = _build_ext.build_ext.boolean_options
+    help_options = _build_ext.build_ext.help_options
+
+    # Add the pyrex specific data.
+    user_options.extend([
+        ('pyrex-cplus', None,
+         "generate C++ source files"),
+        ('pyrex-create-listing', None,
+         "write errors to a listing file"),
+        ('pyrex-include-dirs=', None,
+         "path to the Pyrex include files" + sep_by),
+        ('pyrex-c-in-temp', None,
+         "put generated C files in temp directory"),
+        ('pyrex-gen-pxi', None,
+            "generate .pxi file for public declarations"),
+        ])
+
+    boolean_options.extend([
+        'pyrex-cplus', 'pyrex-create-listing', 'pyrex-c-in-temp'
+    ])
+
+    def initialize_options(self):
+        _build_ext.build_ext.initialize_options(self)
+        self.pyrex_cplus = 0
+        self.pyrex_create_listing = 0
+        self.pyrex_include_dirs = None
+        self.pyrex_c_in_temp = 0
+        self.pyrex_gen_pxi = 0
 
     def finalize_options (self):
-        distutils.command.build_ext.build_ext.finalize_options(self)
-
-        # The following hack should no longer be needed.
-        if 0:
-            # compiling with mingw32 gets an "initializer not a constant" error
-            # doesn't appear to happen with MSVC!
-            # so if we are compiling with mingw32,
-            # switch to C++ mode, to avoid the problem
-            if self.compiler == 'mingw32':
-                self.swig_cpp = 1
-
-    def swig_sources (self, sources, extension = None):
-        if not self.extensions:
-            return
-
-        # collect the names of the source (.pyx) files
-        pyx_sources = []
-        pyx_sources = [source for source in sources if source.endswith('.pyx')]
-        other_sources = [source for source in sources if not source.endswith('.pyx')]
-
-        #suffix = self.swig_cpp and '.cpp' or '.c'
-        suffix = '.c'
-        for pyx in pyx_sources:
-            # should I raise an exception if it doesn't exist?
-            if os.path.exists(pyx):
-                source = pyx
-                target = replace_suffix(source, suffix)
-                if newer(source, target) or self.force:
-                    self.pyrex_compile(source)
-
-        return [replace_suffix(src, suffix) for src in pyx_sources] + other_sources
-
-    def pyrex_compile(self, source):
-        options = CompilationOptions(default_options,
-            include_path = self.include_dirs)
-        result = compile(source, options)
-        if result.num_errors <> 0:
-            sys.exit(1)
+        _build_ext.build_ext.finalize_options(self)
+        if self.pyrex_include_dirs is None:
+            self.pyrex_include_dirs = []
+        elif type(self.pyrex_include_dirs) is StringType:
+            self.pyrex_include_dirs = \
+                string.split(self.pyrex_include_dirs, os.pathsep)
+    # finalize_options ()
+
+    def build_extensions(self):
+        # First, sanity-check the 'extensions' list
+        self.check_extensions_list(self.extensions)
+        for ext in self.extensions:
+            ext.sources = self.pyrex_sources(ext.sources, ext)
+            self.build_extension(ext)
+
+    def pyrex_sources(self, sources, extension):
+
+        """
+        Walk the list of source files in 'sources', looking for Pyrex
+        source (.pyx) files.  Run Pyrex on all that are found, and return
+        a modified 'sources' list with Pyrex source files replaced by the
+        generated C (or C++) files.
+        """
+
+        if PyrexError == None:
+            raise DistutilsPlatformError, \
+                  ("Pyrex does not appear to be installed "
+                   "on platform '%s'") % os.name
+
+        new_sources = []
+        pyrex_sources = []
+        pyrex_targets = {}
+
+        # Setup create_list and cplus from the extension options if
+        # Pyrex.Distutils.extension.Extension is used, otherwise just
+        # use what was parsed from the command-line or the configuration file.
+        # cplus will also be set to true is extension.language is equal to
+        # 'C++' or 'c++'.
+        #try:
+        #      create_listing = self.pyrex_create_listing or \
+        #                                              extension.pyrex_create_listing
+        #      cplus = self.pyrex_cplus or \
+        #                              extension.pyrex_cplus or \
+        #                              (extension.language != None and \
+        #                                      extension.language.lower() == 'c++')
+        #except AttributeError:
+        #      create_listing = self.pyrex_create_listing
+        #      cplus = self.pyrex_cplus or \
+        #                              (extension.language != None and \
+        #                                      extension.language.lower() == 'c++')
+        
+        create_listing = self.pyrex_create_listing or \
+            getattr(extension, 'pyrex_create_listing', 0)
+        cplus = self.pyrex_cplus or getattr(extension, 'pyrex_cplus', 0) or \
+                (extension.language and extension.language.lower() == 'c++')
+        pyrex_gen_pxi = self.pyrex_gen_pxi or getattr(extension, 'pyrex_gen_pxi', 0)
+
+        # Set up the include_path for the Pyres compiler:
+        #      1.      Start with the command line option.
+        #      2.      Add in any (unique) paths from the extension
+        #              pyrex_include_dirs (if Pyrex.Distutils.extension is used).
+        #      3.      Add in any (unique) paths from the extension include_dirs
+        includes = self.pyrex_include_dirs
+        try:
+            for i in extension.pyrex_include_dirs:
+                if not i in includes:
+                    includes.append(i)
+        except AttributeError:
+            pass
+        for i in extension.include_dirs:
+            if not i in includes:
+                includes.append(i)
+
+        # Set the target_ext to '.c'.  Pyrex will change this to '.cpp' if
+        # needed.
+        if cplus:
+            target_ext = '.cpp'
+        else:
+            target_ext = '.c'
+
+        # Decide whether to drop the generated C files into the temp dir
+        # or the source tree.
+
+        if not self.inplace and (self.pyrex_c_in_temp
+                or getattr(extension, 'pyrex_c_in_temp', 0)):
+            target_dir = os.path.join(self.build_temp, "pyrex")
+        else:
+            target_dir = ""
+
+        for source in sources:
+            (base, ext) = os.path.splitext(source)
+            if ext == ".pyx":                    # Pyrex source file
+                new_sources.append(os.path.join(target_dir, base + target_ext))
+                pyrex_sources.append(source)
+                pyrex_targets[source] = new_sources[-1]
+            else:
+                new_sources.append(source)
+
+        if not pyrex_sources:
+            return new_sources
+
+        for source in pyrex_sources:
+            target = pyrex_targets[source]
+            source_time = os.stat(source).st_mtime
+            try:
+                target_time = os.stat(target).st_mtime
+                newer = source_time > target_time
+            except EnvironmentError:
+                newer = 1
+            if newer:
+                log.info("pyrexing %s to %s", source, target)
+                self.mkpath(os.path.dirname(target))
+                options = CompilationOptions(pyrex_default_options, 
+                    use_listing_file = create_listing,
+                    include_path = includes,
+                    output_file = target,
+                    cplus = cplus,
+                    generate_pxi = pyrex_gen_pxi)
+                result = pyrex_compile(source, options=options)
+
+        return new_sources
+
+    # pyrex_sources ()
 
+# class build_ext
index 030dea0ed67a80c88be8ba5dabee8a931540763c..8eae9a0b8be216010203f71224689d6b7475a904 100644 (file)
@@ -6,15 +6,20 @@ verbose = 0
 gcc_pendantic = True
 gcc_warnings_are_errors = True
 gcc_all_warnings = True
+gcc_optimize = False
 
-import os
+import os, sys
 from Pyrex.Utils import replace_suffix
 from Pyrex.Compiler.Errors import PyrexError
 
+version_string = "%s.%s" % sys.version_info[:2]
+
 py_include_dirs = [
-    "/Library/Frameworks/Python.framework/Headers"
+    "/Library/Frameworks/Python.framework/Versions/%s/Headers" % version_string
 ]
 
+os.environ["MACOSX_DEPLOYMENT_TARGET"] = "10.3"
+
 compilers = ["gcc", "g++"]
 compiler_options = \
     "-g -c -fno-strict-aliasing -Wno-long-double -no-cpp-precomp " \
@@ -27,11 +32,16 @@ if gcc_warnings_are_errors:
 if gcc_all_warnings:
     compiler_options.append("-Wall")
     compiler_options.append("-Wno-unused-function")
+if gcc_optimize:
+    compiler_options.append("-O")
 
 linkers = ["gcc", "g++"]
 linker_options = \
-    "-Wl,-F.,-w -bundle -framework Python" \
+    "-Wl,-F.,-w -bundle -undefined dynamic_lookup" \
     .split()
+#linker_options = \
+#      "-Wl,-F.,-w -bundle -framework Python" \
+#      .split()
 
 class CCompilerError(PyrexError):
     pass
index e9722ff79b0e8bd151e810a36c8642e6f823da11..50a751469ab4ce9e652a0282ebdc4aa9e723633f 100644 (file)
@@ -7,7 +7,7 @@ gcc_pendantic = True
 gcc_warnings_are_errors = True
 gcc_all_warnings = True
 
-import os
+import os, sys
 from Pyrex.Utils import replace_suffix
 from Pyrex.Compiler.Errors import PyrexError
 
index 25f7dda85f3e2ee4553715b613539107f1146ec4..2d71d7393cded68d780a3f49f9e03d516fae46c7 100644 (file)
@@ -14,3 +14,21 @@ def open_new_file(path):
     #  preserve metadata on the Mac.
     return open(path, "w+")
 
+def castrate_file(path, st):
+    #  Remove junk contents from an output file after a
+    #  failed compilation, but preserve metadata on Mac.
+    #  Also sets access and modification times back to
+    #  those specified by st (a stat struct).
+    try:
+        f = open(path, "r+")
+    except EnvironmentError:
+        pass
+    else:
+        #st = os.stat(path)
+        f.seek(0, 0)
+        f.truncate()
+        f.write(
+            "#error Do not use this file, it is the result of a failed Pyrex compilation.\n")
+        f.close()
+        if st:
+            os.utime(path, (st.st_atime, st.st_mtime))