Commit 3588f4a6 authored by Stefan Behnel's avatar Stefan Behnel

import of Pyrex 0.9.6.2

parent 5aab5520
......@@ -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)
......
......@@ -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)
......@@ -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.
......@@ -690,49 +747,55 @@ class NameNode(AtomicExprNode):
entry = env.lookup(self.name)
if entry and entry.is_type and entry.type.is_extension_type:
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,7 +856,8 @@ 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)))
else:
......@@ -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:
......@@ -969,18 +1036,16 @@ class ExcValueNode(AtomicExprNode):
# 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,
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 = [
......
......@@ -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:
......
......@@ -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)
def generate_h_code(self, env, result):
public_vars_and_funcs = []
self.generate_h_code(env, options, result)
self.generate_api_code(env, result)
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))
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:
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:
self.generate_cclass_header_code(entry.type, h_code)
self.generate_cclass_include_code(entry.type, i_code)
h_code.putln("PyMODINIT_FUNC init%s(void);" % env.module_name)
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
......@@ -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,18 +1218,30 @@ 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)
......@@ -1130,13 +1315,52 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
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:
#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;
}
"""]
......@@ -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_"
......@@ -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
......@@ -471,13 +511,14 @@ 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)
......@@ -967,19 +1063,19 @@ 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")
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) < 0) return %s;" % (
"if (__Pyx_GetStarArgs(&%s, &%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(),
nargs,
star_arg_addr,
starstar_arg_addr,
self.reqd_kw_flags_cname,
self.error_value()))
def generate_argument_conversion_code(self, code):
......@@ -1646,10 +1742,9 @@ 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:
# 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):
......@@ -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,23 +2278,29 @@ class TryFinallyStatNode(StatNode):
"}")
code.putln(
"/*finally:*/ {")
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;")
#code.putln(
# "PyObject *%s, *%s, *%s;" %
# self.exc_vars)
#code.putln(
# "int %s;" %
# self.lineno_var)
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 range(len(new_labels)):
"__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 in code.labels_used:
if new_label == new_error_label:
#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:
......@@ -2195,19 +2311,35 @@ class TryFinallyStatNode(StatNode):
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)
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]))
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))
#if PY_VERSION_HEX < 0x02050000
if (PyInstance_Check(type)) {
type = (PyObject*) ((PyInstanceObject*)type)->in_class;
else
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);
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;
}
"""]
#------------------------------------------------------------------------------------
......@@ -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,6 +667,9 @@ def p_expression_or_assignment(s):
expr_list.append(p_expr(s))
if len(expr_list) == 1:
expr = expr_list[0]
if isinstance(expr, ExprNodes.StringNode):
return Nodes.PassStatNode(expr.pos)
else:
return Nodes.ExprStatNode(expr.pos, expr = expr)
else:
expr_list_list = []
......@@ -769,10 +794,13 @@ def p_raise_statement(s):
if s.sy == ',':
s.next()
exc_tb = p_simple_expr(s)
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,6 +1070,7 @@ def p_include_statement(s, level):
s.next() # 'include'
_, include_file_name = p_string_literal(s)
s.expect_newline("Syntax error in include statement")
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")
......@@ -1050,6 +1082,20 @@ def p_include_statement(s, level):
return tree
else:
return None
else:
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,20 +1141,76 @@ 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)
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 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':
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)
......@@ -1117,16 +1219,15 @@ def p_statement(s, level, cdef_flag = 0, visibility = 'private'):
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")
#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)
else:
if level in ('c_class', 'c_class_pxd'):
if s.sy == 'pass':
elif s.sy == 'pass' and level <> 'property':
return p_pass_statement(s, with_newline = 1)
else:
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)
......@@ -1136,22 +1237,26 @@ def p_statement(s, level, cdef_flag = 0, visibility = 'private'):
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))
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,28 +1392,75 @@ 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 == '(':
s.next()
result = p_c_declarator(s, empty, is_type, cmethod_flag)
s.expect(')')
else:
if s.sy == 'IDENT':
name = s.systring
......@@ -1331,31 +1471,29 @@ def p_c_declarator(s, empty = 0, is_type = 0, cmethod_flag = 0):
s.next()
cname = p_opt_cname(s)
else:
if nonempty:
error(s.position(), "Empty declarator")
name = ""
cname = None
result = Nodes.CNameDeclaratorNode(pos,
name = name, cname = cname)
while s.sy in ('[', '('):
if s.sy == '[':
result.calling_convention = calling_convention
return result
def p_nogil(s):
if s.sy == 'IDENT' and s.systring == 'nogil':
s.next()
if s.sy <> ']':
dim = p_expr(s)
return 1
else:
dim = None
s.expect(']')
result = Nodes.CArrayDeclaratorNode(pos,
base = result, dimension = dim)
else: # sy == '('
return 0
def p_with_gil(s):
if s.sy == 'with':
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
return result
s.expect_keyword('gil')
return 1
else:
return 0
def p_exception_value_clause(s):
exc_val = None
......@@ -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:
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
args.append(p_c_arg_decl(s, in_pyfunc))
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()
if s.sy == 'IDENT':
star_arg = p_py_arg_decl(s)
if s.sy == ',':
s.next()
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)
elif 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,
......
......@@ -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
......@@ -112,16 +128,19 @@ class PyrexType:
# 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,11 +151,24 @@ 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 __str__(self):
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.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):
......@@ -471,30 +505,47 @@ class CFuncType(CType):
# has_varargs boolean
# exception_value string
# 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_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_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_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(5, "T_FLOAT")
c_double_type = CFloatType(6, "T_DOUBLE")
c_longdouble_type = CFloatType(7)
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.
......
......@@ -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,6 +356,15 @@ class PyrexScanner(Scanner):
if self.sy == what:
self.next()
else:
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:
......@@ -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)
......@@ -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,10 +94,13 @@ 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
......@@ -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.
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 visibility <> 'private':
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,9 +1030,14 @@ 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:
......@@ -986,8 +1045,13 @@ class CClassScope(ClassScope):
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:
......
......@@ -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,
......@@ -81,23 +83,43 @@ 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:
# Abstract base class for type slot descriptors.
#
# slot_name string Member name of the slot in the type object
# is_initialised_dynamically Is initialised by code in the module init function
# flag Py_TPFLAGS_XXX value indicating presence of slot
def __init__(self, slot_name, dynamic = 0):
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__")
......
version = '0.9.5.1a'
version = '0.9.6.2'
......@@ -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)
......
# 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
# 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
......@@ -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
......
......@@ -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
......
......@@ -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))
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment