Commit 7bf952b2 authored by Stefan Behnel's avatar Stefan Behnel

merge

parents f1d9c4af 8b2a1153
...@@ -1226,7 +1226,7 @@ class IndexNode(ExprNode): ...@@ -1226,7 +1226,7 @@ class IndexNode(ExprNode):
# base ExprNode # base ExprNode
# index ExprNode # index ExprNode
subexprs = ['base', 'index', 'py_index'] subexprs = ['base', 'index']
def compile_time_value(self, denv): def compile_time_value(self, denv):
base = self.base.compile_time_value(denv) base = self.base.compile_time_value(denv)
...@@ -1243,19 +1243,27 @@ class IndexNode(ExprNode): ...@@ -1243,19 +1243,27 @@ class IndexNode(ExprNode):
pass pass
def analyse_types(self, env): def analyse_types(self, env):
self.analyse_base_and_index_types(env, getting = 1)
def analyse_target_types(self, env):
self.analyse_base_and_index_types(env, setting = 1)
def analyse_base_and_index_types(self, env, getting = 0, setting = 0):
self.base.analyse_types(env) self.base.analyse_types(env)
self.index.analyse_types(env) self.index.analyse_types(env)
if self.base.type.is_pyobject: if self.base.type.is_pyobject:
if self.index.type.is_int: if self.index.type.is_int:
self.original_index_type = self.index.type
self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env) self.index = self.index.coerce_to(PyrexTypes.c_py_ssize_t_type, env).coerce_to_simple(env)
self.py_index = CloneNode(self.index).coerce_to_pyobject(env) if getting:
env.use_utility_code(getitem_int_utility_code)
if setting:
env.use_utility_code(setitem_int_utility_code)
else: else:
self.index = self.index.coerce_to_pyobject(env) self.index = self.index.coerce_to_pyobject(env)
self.py_index = CloneNode(self.index)
self.type = py_object_type self.type = py_object_type
self.is_temp = 1 self.is_temp = 1
else: else:
self.py_index = CloneNode(self.index) # so that it exists for subexpr processing
if self.base.type.is_ptr or self.base.type.is_array: if self.base.type.is_ptr or self.base.type.is_array:
self.type = self.base.type.base_type self.type = self.base.type.base_type
else: else:
...@@ -1282,78 +1290,62 @@ class IndexNode(ExprNode): ...@@ -1282,78 +1290,62 @@ class IndexNode(ExprNode):
return "(%s[%s])" % ( return "(%s[%s])" % (
self.base.result_code, self.index.result_code) self.base.result_code, self.index.result_code)
def index_unsigned_parameter(self):
if self.index.type.is_int:
if self.original_index_type.signed:
return ", 0"
else:
return ", sizeof(Py_ssize_t) <= sizeof(%s)" % self.original_index_type.declaration_code("")
else:
return ""
def generate_subexpr_evaluation_code(self, code): def generate_subexpr_evaluation_code(self, code):
# do not evaluate self.py_index in case we don't need it
self.base.generate_evaluation_code(code) self.base.generate_evaluation_code(code)
self.index.generate_evaluation_code(code) self.index.generate_evaluation_code(code)
def generate_subexpr_disposal_code(self, code): def generate_subexpr_disposal_code(self, code):
# if we used self.py_index, it will be disposed of manually
self.base.generate_disposal_code(code) self.base.generate_disposal_code(code)
self.index.generate_disposal_code(code) self.index.generate_disposal_code(code)
def generate_result_code(self, code): def generate_result_code(self, code):
if self.type.is_pyobject: if self.type.is_pyobject:
if self.index.type.is_int: if self.index.type.is_int:
code.putln("if (PyList_CheckExact(%s) && 0 <= %s && %s < PyList_GET_SIZE(%s)) {" % ( function = "__Pyx_GetItemInt"
self.base.py_result(), index_code = self.index.result_code
self.index.result_code, else:
self.index.result_code, function = "PyObject_GetItem"
self.base.py_result())) index_code = self.index.py_result()
code.putln("%s = PyList_GET_ITEM(%s, %s); Py_INCREF(%s);" % ( sign_code = ""
code.putln(
"%s = %s(%s, %s%s); if (!%s) %s" % (
self.result_code, self.result_code,
function,
self.base.py_result(), self.base.py_result(),
self.index.result_code, index_code,
self.result_code)) self.index_unsigned_parameter(),
code.putln("} else if (PyTuple_CheckExact(%s) && 0 <= %s && %s < PyTuple_GET_SIZE(%s)) {" % (
self.base.py_result(),
self.index.result_code,
self.index.result_code,
self.base.py_result()))
code.putln("%s = PyTuple_GET_ITEM(%s, %s); Py_INCREF(%s);" % (
self.result_code, self.result_code,
self.base.py_result(), code.error_goto(self.pos)))
self.index.result_code,
self.result_code))
code.putln("} else {")
self.generate_generic_code_result(code)
code.putln("}")
else:
self.generate_generic_code_result(code)
def generate_generic_code_result(self, code): def generate_setitem_code(self, value_code, code):
self.py_index.generate_result_code(code) if self.index.type.is_int:
function = "__Pyx_SetItemInt"
index_code = self.index.result_code
else:
function = "PyObject_SetItem"
index_code = self.index.py_result()
code.putln( code.putln(
"%s = PyObject_GetItem(%s, %s); %s" % ( "if (%s(%s, %s, %s%s) < 0) %s" % (
self.result_code, function,
self.base.py_result(), self.base.py_result(),
self.py_index.py_result(), index_code,
code.error_goto_if_null(self.result_code, self.pos))) value_code,
if self.is_temp: self.index_unsigned_parameter(),
self.py_index.generate_disposal_code(code) code.error_goto(self.pos)))
def generate_assignment_code(self, rhs, code): def generate_assignment_code(self, rhs, code):
self.generate_subexpr_evaluation_code(code) self.generate_subexpr_evaluation_code(code)
if self.type.is_pyobject: if self.type.is_pyobject:
if self.index.type.is_int: self.generate_setitem_code(rhs.py_result(), code)
code.putln("if (PyList_CheckExact(%s) && 0 <= %s && %s < PyList_GET_SIZE(%s)) {" % (
self.base.py_result(),
self.index.result_code,
self.index.result_code,
self.base.py_result()))
code.putln("Py_DECREF(PyList_GET_ITEM(%s, %s)); Py_INCREF(%s);" % (
self.base.py_result(),
self.index.result_code,
rhs.py_result()))
code.putln("PyList_SET_ITEM(%s, %s, %s);" % (
self.base.py_result(),
self.index.result_code,
rhs.py_result()))
code.putln("} else {")
self.generate_generic_assignment_code(rhs, code)
code.putln("}")
else:
self.generate_generic_assignment_code(rhs, code)
else: else:
code.putln( code.putln(
"%s = %s;" % ( "%s = %s;" % (
...@@ -1361,25 +1353,22 @@ class IndexNode(ExprNode): ...@@ -1361,25 +1353,22 @@ class IndexNode(ExprNode):
self.generate_subexpr_disposal_code(code) self.generate_subexpr_disposal_code(code)
rhs.generate_disposal_code(code) rhs.generate_disposal_code(code)
def generate_generic_assignment_code(self, rhs, code):
self.py_index.generate_result_code(code)
code.put_error_if_neg(self.pos,
"PyObject_SetItem(%s, %s, %s)" % (
self.base.py_result(),
self.py_index.py_result(),
rhs.py_result()))
if self.is_temp:
self.py_index.generate_disposal_code(code)
def generate_deletion_code(self, code): def generate_deletion_code(self, code):
self.generate_subexpr_evaluation_code(code) self.generate_subexpr_evaluation_code(code)
self.py_index.generate_evaluation_code(code) #if self.type.is_pyobject:
code.put_error_if_neg(self.pos, if self.index.type.is_int:
"PyObject_DelItem(%s, %s)" % ( function = "PySequence_DelItem"
index_code = self.index.result_code
else:
function = "PyObject_DelItem"
index_code = self.index.py_result()
code.putln(
"if (%s(%s, %s) < 0) %s" % (
function,
self.base.py_result(), self.base.py_result(),
self.py_index.py_result())) index_code,
code.error_goto(self.pos)))
self.generate_subexpr_disposal_code(code) self.generate_subexpr_disposal_code(code)
self.py_index.generate_disposal_code(code)
class SliceIndexNode(ExprNode): class SliceIndexNode(ExprNode):
...@@ -2737,9 +2726,8 @@ class TypecastNode(ExprNode): ...@@ -2737,9 +2726,8 @@ class TypecastNode(ExprNode):
if from_py and not to_py and self.operand.is_ephemeral() and not self.type.is_numeric: if from_py and not to_py and self.operand.is_ephemeral() and not self.type.is_numeric:
error(self.pos, "Casting temporary Python object to non-numeric non-Python type") error(self.pos, "Casting temporary Python object to non-numeric non-Python type")
if to_py and not from_py: if to_py and not from_py:
self.result_ctype = py_object_type
self.is_temp = 1
if self.operand.type.to_py_function: if self.operand.type.to_py_function:
self.result_ctype = py_object_type
self.operand = self.operand.coerce_to_pyobject(env) self.operand = self.operand.coerce_to_pyobject(env)
else: else:
warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type)) warning(self.pos, "No conversion from %s to %s, python object pointer used." % (self.operand.type, self.type))
...@@ -3850,9 +3838,6 @@ class CloneNode(CoercionNode): ...@@ -3850,9 +3838,6 @@ class CloneNode(CoercionNode):
if hasattr(self.arg, 'entry'): if hasattr(self.arg, 'entry'):
self.entry = self.arg.entry self.entry = self.arg.entry
#def result_as_extension_type(self):
# return self.arg.result_as_extension_type()
def generate_evaluation_code(self, code): def generate_evaluation_code(self, code):
pass pass
...@@ -4138,3 +4123,62 @@ static void __Pyx_TypeModified(PyTypeObject* type) { ...@@ -4138,3 +4123,62 @@ static void __Pyx_TypeModified(PyTypeObject* type) {
#endif #endif
""" """
] ]
#------------------------------------------------------------------------------------
# If the is_unsigned flag is set, we need to do some extra work to make
# sure the index doesn't become negative.
getitem_int_utility_code = [
"""
static INLINE PyObject *__Pyx_GetItemInt(PyObject *o, Py_ssize_t i, int is_unsigned) {
PyObject *r;
if (PyList_CheckExact(o) && 0 <= i && i < PyList_GET_SIZE(o)) {
r = PyList_GET_ITEM(o, i);
Py_INCREF(r);
}
else if (PyTuple_CheckExact(o) && 0 <= i && i < PyTuple_GET_SIZE(o)) {
r = PyTuple_GET_ITEM(o, i);
Py_INCREF(r);
}
else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_item && (likely(i >= 0) || !is_unsigned))
r = PySequence_GetItem(o, i);
else {
PyObject *j = (likely(i >= 0) || !is_unsigned) ? PyInt_FromLong(i) : PyLong_FromUnsignedLongLong((sizeof(unsigned long long) > sizeof(Py_ssize_t) ? (1ULL << (sizeof(Py_ssize_t)*8)) : 0) + i);
if (!j)
return 0;
r = PyObject_GetItem(o, j);
Py_DECREF(j);
}
return r;
}
""",
"""
"""]
#------------------------------------------------------------------------------------
setitem_int_utility_code = [
"""
static INLINE int __Pyx_SetItemInt(PyObject *o, Py_ssize_t i, PyObject *v, int is_unsigned) {
int r;
if (PyList_CheckExact(o) && 0 <= i && i < PyList_GET_SIZE(o)) {
Py_DECREF(PyList_GET_ITEM(o, i));
Py_INCREF(v);
PyList_SET_ITEM(o, i, v);
return 1;
}
else if (Py_TYPE(o)->tp_as_sequence && Py_TYPE(o)->tp_as_sequence->sq_ass_item && (likely(i >= 0) || !is_unsigned))
r = PySequence_SetItem(o, i, v);
else {
PyObject *j = (likely(i >= 0) || !is_unsigned) ? PyInt_FromLong(i) : PyLong_FromUnsignedLongLong((sizeof(unsigned long long) > sizeof(Py_ssize_t) ? (1ULL << (sizeof(Py_ssize_t)*8)) : 0) + i);
if (!j)
return -1;
r = PyObject_SetItem(o, j, v);
Py_DECREF(j);
}
return r;
}
""",
"""
"""]
...@@ -68,7 +68,9 @@ def make_lexicon(): ...@@ -68,7 +68,9 @@ def make_lexicon():
bra = Any("([{") bra = Any("([{")
ket = Any(")]}") ket = Any(")]}")
punct = Any(":,;+-*/|&<>=.%`~^?") punct = Any(":,;+-*/|&<>=.%`~^?")
diphthong = Str("==", "<>", "!=", "<=", ">=", "<<", ">>", "**", "+=", "-=", "*=", "/=", "%=", "|=", "^=", "&=", "//") diphthong = Str("==", "<>", "!=", "<=", ">=", "<<", ">>", "**", "//",
"+=", "-=", "*=", "/=", "%=", "|=", "^=", "&=",
"<<=", ">>=", "**=", "//=")
spaces = Rep1(Any(" \t\f")) spaces = Rep1(Any(" \t\f"))
comment = Str("#") + Rep(AnyBut("\n")) comment = Str("#") + Rep(AnyBut("\n"))
escaped_newline = Str("\\\n") escaped_newline = Str("\\\n")
......
...@@ -230,6 +230,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -230,6 +230,8 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
self.generate_typeobj_definitions(env, code) self.generate_typeobj_definitions(env, code)
self.generate_method_table(env, code) self.generate_method_table(env, code)
self.generate_filename_init_prototype(code) self.generate_filename_init_prototype(code)
if env.has_import_star:
self.generate_import_star(env, code)
self.generate_module_init_func(modules[:-1], env, code) self.generate_module_init_func(modules[:-1], env, code)
code.mark_pos(None) code.mark_pos(None)
self.generate_module_cleanup_func(env, code) self.generate_module_cleanup_func(env, code)
...@@ -1431,6 +1433,66 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1431,6 +1433,66 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
code.putln(""); code.putln("");
code.putln("static void %s(void); /*proto*/" % Naming.fileinit_cname) code.putln("static void %s(void); /*proto*/" % Naming.fileinit_cname)
def generate_import_star(self, env, code):
code.putln()
code.putln("char* %s_type_names[] = {" % Naming.import_star)
for name, entry in env.entries.items():
if entry.is_type:
code.putln('"%s",' % name)
code.putln("0")
code.putln("};")
code.putln()
code.putln("static int %s(PyObject *o, PyObject* py_name, char *name) {" % Naming.import_star_set)
code.putln("char** type_name = %s_type_names;" % Naming.import_star)
code.putln("while (*type_name) {")
code.putln("if (!strcmp(name, *type_name)) {")
code.putln('PyErr_Format(PyExc_TypeError, "Cannot overwrite C type %s", name);')
code.putln('goto bad;')
code.putln("}")
code.putln("type_name++;")
code.putln("}")
old_error_label = code.new_error_label()
code.putln("if (0);") # so the first one can be "else if"
for name, entry in env.entries.items():
if entry.is_cglobal and entry.used:
code.putln('else if (!strcmp(name, "%s")) {' % name)
if entry.type.is_pyobject:
if entry.type.is_extension_type or entry.type.is_builtin_type:
code.putln("if (!(%s)) %s;" % (
entry.type.type_test_code("o"),
code.error_goto(entry.pos)))
code.put_var_decref(entry)
code.putln("%s = %s;" % (
entry.cname,
PyrexTypes.typecast(entry.type, py_object_type, "o")))
elif entry.type.from_py_function:
rhs = "%s(o)" % entry.type.from_py_function
if entry.type.is_enum:
rhs = typecast(entry.type, c_long_type, rhs)
code.putln("%s = %s; if (%s) %s;" % (
entry.cname,
rhs,
entry.type.error_condition(entry.cname),
code.error_goto(entry.pos)))
code.putln("Py_DECREF(o);")
else:
code.putln('PyErr_Format(PyExc_TypeError, "Cannot convert Python object %s to %s");' % (name, entry.type))
code.putln(code.error_goto(entry.pos))
code.putln("}")
code.putln("else {")
code.putln("if (PyObject_SetAttr(%s, py_name, o) < 0) goto bad;" % Naming.module_cname)
code.putln("}")
code.putln("return 0;")
code.put_label(code.error_label)
# This helps locate the offending name.
code.putln('__Pyx_AddTraceback("%s");' % self.full_module_name);
code.error_label = old_error_label
code.putln("bad:")
code.putln("Py_DECREF(o);")
code.putln("return -1;")
code.putln("}")
code.putln(import_star_utility_code)
def generate_module_init_func(self, imported_modules, env, code): def generate_module_init_func(self, imported_modules, env, code):
code.putln("") code.putln("")
header = "PyMODINIT_FUNC init%s(void)" % env.module_name header = "PyMODINIT_FUNC init%s(void)" % env.module_name
...@@ -1544,6 +1606,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): ...@@ -1544,6 +1606,9 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode):
"if (!%s) %s;" % ( "if (!%s) %s;" % (
env.module_cname, env.module_cname,
code.error_goto(self.pos))); code.error_goto(self.pos)));
code.putln(
"Py_INCREF(%s);" %
env.module_cname)
code.putln( code.putln(
'%s = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME);' % '%s = PyImport_AddModule(__Pyx_BUILTIN_MODULE_NAME);' %
Naming.builtins_cname) Naming.builtins_cname)
...@@ -2017,3 +2082,94 @@ bad: ...@@ -2017,3 +2082,94 @@ bad:
return ret; return ret;
} }
"""] """]
import_star_utility_code = """
/* import_all_from is an unexposed function from ceval.c */
static int
__Pyx_import_all_from(PyObject *locals, PyObject *v)
{
PyObject *all = PyObject_GetAttrString(v, "__all__");
PyObject *dict, *name, *value;
int skip_leading_underscores = 0;
int pos, err;
if (all == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1; /* Unexpected error */
PyErr_Clear();
dict = PyObject_GetAttrString(v, "__dict__");
if (dict == NULL) {
if (!PyErr_ExceptionMatches(PyExc_AttributeError))
return -1;
PyErr_SetString(PyExc_ImportError,
"from-import-* object has no __dict__ and no __all__");
return -1;
}
all = PyMapping_Keys(dict);
Py_DECREF(dict);
if (all == NULL)
return -1;
skip_leading_underscores = 1;
}
for (pos = 0, err = 0; ; pos++) {
name = PySequence_GetItem(all, pos);
if (name == NULL) {
if (!PyErr_ExceptionMatches(PyExc_IndexError))
err = -1;
else
PyErr_Clear();
break;
}
if (skip_leading_underscores &&
PyString_Check(name) &&
PyString_AS_STRING(name)[0] == '_')
{
Py_DECREF(name);
continue;
}
value = PyObject_GetAttr(v, name);
if (value == NULL)
err = -1;
else if (PyDict_CheckExact(locals))
err = PyDict_SetItem(locals, name, value);
else
err = PyObject_SetItem(locals, name, value);
Py_DECREF(name);
Py_XDECREF(value);
if (err != 0)
break;
}
Py_DECREF(all);
return err;
}
static int %s(PyObject* m) {
int i;
int ret = -1;
PyObject *locals = 0;
PyObject *list = 0;
PyObject *name;
PyObject *item;
locals = PyDict_New(); if (!locals) goto bad;
if (__Pyx_import_all_from(locals, m) < 0) goto bad;
list = PyDict_Items(locals); if (!list) goto bad;
for(i=0; i<PyList_GET_SIZE(list); i++) {
name = PyTuple_GET_ITEM(PyList_GET_ITEM(list, i), 0);
item = PyTuple_GET_ITEM(PyList_GET_ITEM(list, i), 1);
if (%s(item, name, PyString_AsString(name)) < 0) goto bad;
}
ret = 0;
bad:
Py_XDECREF(locals);
Py_XDECREF(list);
return ret;
}
""" % ( Naming.import_star, Naming.import_star_set )
...@@ -67,6 +67,8 @@ print_function_kwargs = pyrex_prefix + "print_kwargs" ...@@ -67,6 +67,8 @@ print_function_kwargs = pyrex_prefix + "print_kwargs"
cleanup_cname = pyrex_prefix + "module_cleanup" cleanup_cname = pyrex_prefix + "module_cleanup"
optional_args_cname = pyrex_prefix + "optional_args" optional_args_cname = pyrex_prefix + "optional_args"
no_opt_args = pyrex_prefix + "no_opt_args" no_opt_args = pyrex_prefix + "no_opt_args"
import_star = pyrex_prefix + "import_star"
import_star_set = pyrex_prefix + "import_star_set"
line_c_macro = "__LINE__" line_c_macro = "__LINE__"
......
...@@ -2440,21 +2440,34 @@ class InPlaceAssignmentNode(AssignmentNode): ...@@ -2440,21 +2440,34 @@ class InPlaceAssignmentNode(AssignmentNode):
self.rhs.generate_evaluation_code(code) self.rhs.generate_evaluation_code(code)
self.dup.generate_subexpr_evaluation_code(code) self.dup.generate_subexpr_evaluation_code(code)
self.dup.generate_result_code(code) self.dup.generate_result_code(code)
if self.operator == "**":
extra = ", Py_None"
else:
extra = ""
if self.lhs.type.is_pyobject: if self.lhs.type.is_pyobject:
code.putln( code.putln(
"%s = %s(%s, %s); %s" % ( "%s = %s(%s, %s%s); %s" % (
self.result.result_code, self.result.result_code,
self.py_operation_function(), self.py_operation_function(),
self.dup.py_result(), self.dup.py_result(),
self.rhs.py_result(), self.rhs.py_result(),
extra,
code.error_goto_if_null(self.result.py_result(), self.pos))) code.error_goto_if_null(self.result.py_result(), self.pos)))
self.result.generate_evaluation_code(code) # May be a type check... self.result.generate_evaluation_code(code) # May be a type check...
self.rhs.generate_disposal_code(code) self.rhs.generate_disposal_code(code)
self.dup.generate_disposal_code(code) self.dup.generate_disposal_code(code)
self.lhs.generate_assignment_code(self.result, code) self.lhs.generate_assignment_code(self.result, code)
else: else:
c_op = self.operator
if c_op == "//":
c_op = "/"
elif c_op == "**":
if self.lhs.type.is_int and self.rhs.type.is_int:
error(self.pos, "** with two C int types is ambiguous")
else:
error(self.pos, "No C inplace power operator")
# have to do assignment directly to avoid side-effects # have to do assignment directly to avoid side-effects
code.putln("%s %s= %s;" % (self.lhs.result_code, self.operator, self.rhs.result_code) ) code.putln("%s %s= %s;" % (self.lhs.result_code, c_op, self.rhs.result_code) )
self.rhs.generate_disposal_code(code) self.rhs.generate_disposal_code(code)
if self.dup.is_temp: if self.dup.is_temp:
self.dup.generate_subexpr_disposal_code(code) self.dup.generate_subexpr_disposal_code(code)
...@@ -2484,6 +2497,10 @@ class InPlaceAssignmentNode(AssignmentNode): ...@@ -2484,6 +2497,10 @@ class InPlaceAssignmentNode(AssignmentNode):
"*": "PyNumber_InPlaceMultiply", "*": "PyNumber_InPlaceMultiply",
"/": "PyNumber_InPlaceDivide", "/": "PyNumber_InPlaceDivide",
"%": "PyNumber_InPlaceRemainder", "%": "PyNumber_InPlaceRemainder",
"<<": "PyNumber_InPlaceLshift",
">>": "PyNumber_InPlaceRshift",
"**": "PyNumber_InPlacePower",
"//": "PyNumber_InPlaceFloorDivide",
} }
def annotate(self, code): def annotate(self, code):
...@@ -3648,6 +3665,10 @@ class FromCImportStatNode(StatNode): ...@@ -3648,6 +3665,10 @@ class FromCImportStatNode(StatNode):
module_scope = env.find_module(self.module_name, self.pos) module_scope = env.find_module(self.module_name, self.pos)
env.add_imported_module(module_scope) env.add_imported_module(module_scope)
for pos, name, as_name in self.imported_names: for pos, name, as_name in self.imported_names:
if name == "*":
for local_name, entry in module_scope.entries.items():
env.add_imported_entry(local_name, entry, pos)
else:
entry = module_scope.find(name, pos) entry = module_scope.find(name, pos)
if entry: if entry:
local_name = as_name or name local_name = as_name or name
...@@ -3667,11 +3688,20 @@ class FromImportStatNode(StatNode): ...@@ -3667,11 +3688,20 @@ class FromImportStatNode(StatNode):
# items [(string, NameNode)] # items [(string, NameNode)]
# interned_items [(string, NameNode)] # interned_items [(string, NameNode)]
# item PyTempNode used internally # item PyTempNode used internally
# import_star boolean used internally
child_attrs = ["module"] child_attrs = ["module"]
import_star = 0
def analyse_declarations(self, env): def analyse_declarations(self, env):
for _, target in self.items: for name, target in self.items:
if name == "*":
if not env.is_module_scope:
error(self.pos, "import * only allowed at module level")
return
env.has_import_star = 1
self.import_star = 1
else:
target.analyse_target_declaration(env) target.analyse_target_declaration(env)
def analyse_expressions(self, env): def analyse_expressions(self, env):
...@@ -3681,6 +3711,12 @@ class FromImportStatNode(StatNode): ...@@ -3681,6 +3711,12 @@ class FromImportStatNode(StatNode):
self.item.allocate_temp(env) self.item.allocate_temp(env)
self.interned_items = [] self.interned_items = []
for name, target in self.items: for name, target in self.items:
if name == '*':
for _, entry in env.entries.items():
if not entry.is_type and entry.type.is_extension_type:
env.use_utility_code(ExprNodes.type_test_utility_code)
break
else:
self.interned_items.append( self.interned_items.append(
(env.intern_identifier(name), target)) (env.intern_identifier(name), target))
target.analyse_target_expression(env, None) target.analyse_target_expression(env, None)
...@@ -3690,6 +3726,12 @@ class FromImportStatNode(StatNode): ...@@ -3690,6 +3726,12 @@ class FromImportStatNode(StatNode):
def generate_execution_code(self, code): def generate_execution_code(self, code):
self.module.generate_evaluation_code(code) self.module.generate_evaluation_code(code)
if self.import_star:
code.putln(
'if (%s(%s) < 0) %s;' % (
Naming.import_star,
self.module.py_result(),
code.error_goto(self.pos)))
for cname, target in self.interned_items: for cname, target in self.interned_items:
code.putln( code.putln(
'%s = PyObject_GetAttr(%s, %s); %s' % ( '%s = PyObject_GetAttr(%s, %s); %s' % (
......
...@@ -755,11 +755,11 @@ def p_expression_or_assignment(s): ...@@ -755,11 +755,11 @@ def p_expression_or_assignment(s):
s.next() s.next()
expr_list.append(p_expr(s)) expr_list.append(p_expr(s))
if len(expr_list) == 1: if len(expr_list) == 1:
if re.match("[+*/\%^\&|-]=", s.sy): if re.match(r"([+*/\%^\&|-]|<<|>>|\*\*|//)=", s.sy):
lhs = expr_list[0] lhs = expr_list[0]
if not isinstance(lhs, (ExprNodes.AttributeNode, ExprNodes.IndexNode, ExprNodes.NameNode) ): if not isinstance(lhs, (ExprNodes.AttributeNode, ExprNodes.IndexNode, ExprNodes.NameNode) ):
error(lhs.pos, "Illegal operand for inplace operation.") error(lhs.pos, "Illegal operand for inplace operation.")
operator = s.sy[0] operator = s.sy[:-1]
s.next() s.next()
rhs = p_expr(s) rhs = p_expr(s)
return Nodes.InPlaceAssignmentNode(lhs.pos, operator = operator, lhs = lhs, rhs = rhs) return Nodes.InPlaceAssignmentNode(lhs.pos, operator = operator, lhs = lhs, rhs = rhs)
...@@ -944,7 +944,10 @@ def p_from_import_statement(s, first_statement = 0): ...@@ -944,7 +944,10 @@ def p_from_import_statement(s, first_statement = 0):
else: else:
s.error("Expected 'import' or 'cimport'") s.error("Expected 'import' or 'cimport'")
if s.sy == '*': if s.sy == '*':
s.error("'import *' not supported") # s.error("'import *' not supported")
imported_names = [(s.position(), "*", None)]
s.next()
else:
imported_names = [p_imported_name(s)] imported_names = [p_imported_name(s)]
while s.sy == ',': while s.sy == ',':
s.next() s.next()
...@@ -1080,9 +1083,13 @@ def p_for_bounds(s): ...@@ -1080,9 +1083,13 @@ def p_for_bounds(s):
s.next() s.next()
iterator = p_for_iterator(s) iterator = p_for_iterator(s)
return { 'target': target, 'iterator': iterator } return { 'target': target, 'iterator': iterator }
elif s.sy == 'from': else:
if s.sy == 'from':
s.next() s.next()
bound1 = p_bit_expr(s) bound1 = p_bit_expr(s)
else:
# Support shorter "for a <= x < b" syntax
bound1, target = target, None
rel1 = p_for_from_relation(s) rel1 = p_for_from_relation(s)
name2_pos = s.position() name2_pos = s.position()
name2 = p_ident(s) name2 = p_ident(s)
...@@ -1090,6 +1097,9 @@ def p_for_bounds(s): ...@@ -1090,6 +1097,9 @@ def p_for_bounds(s):
rel2 = p_for_from_relation(s) rel2 = p_for_from_relation(s)
bound2 = p_bit_expr(s) bound2 = p_bit_expr(s)
step = p_for_from_step(s) step = p_for_from_step(s)
if target is None:
target = ExprNodes.NameNode(name2_pos, name = name2)
else:
if not target.is_name: if not target.is_name:
error(target.pos, error(target.pos,
"Target of for-from statement must be a variable name") "Target of for-from statement must be a variable name")
...@@ -1105,8 +1115,6 @@ def p_for_bounds(s): ...@@ -1105,8 +1115,6 @@ def p_for_bounds(s):
'relation2': rel2, 'relation2': rel2,
'bound2': bound2, 'bound2': bound2,
'step': step } 'step': step }
else:
s.error("Expected 'in' or 'from'")
def p_for_from_relation(s): def p_for_from_relation(s):
if s.sy in inequality_relations: if s.sy in inequality_relations:
...@@ -1286,7 +1294,7 @@ def p_DEF_statement(s): ...@@ -1286,7 +1294,7 @@ def p_DEF_statement(s):
return Nodes.PassStatNode(pos) return Nodes.PassStatNode(pos)
def p_IF_statement(s, level, cdef_flag, visibility, api): def p_IF_statement(s, level, cdef_flag, visibility, api):
pos = s.position pos = s.position()
saved_eval = s.compile_time_eval saved_eval = s.compile_time_eval
current_eval = saved_eval current_eval = saved_eval
denv = s.compile_time_env denv = s.compile_time_env
......
...@@ -693,8 +693,10 @@ class ModuleScope(Scope): ...@@ -693,8 +693,10 @@ class ModuleScope(Scope):
# interned_nums [int/long] Interned numeric constants # interned_nums [int/long] Interned numeric constants
# all_pystring_entries [Entry] Python string consts from all scopes # all_pystring_entries [Entry] Python string consts from all scopes
# types_imported {PyrexType : 1} Set of types for which import code generated # types_imported {PyrexType : 1} Set of types for which import code generated
# has_import_star boolean Module contains import *
is_module_scope = 1 is_module_scope = 1
has_import_star = 0
def __init__(self, name, parent_module, context): def __init__(self, name, parent_module, context):
self.parent_module = parent_module self.parent_module = parent_module
...@@ -734,7 +736,10 @@ class ModuleScope(Scope): ...@@ -734,7 +736,10 @@ class ModuleScope(Scope):
def declare_builtin(self, name, pos): def declare_builtin(self, name, pos):
if not hasattr(__builtin__, name): if not hasattr(__builtin__, name):
if self.outer_scope is not None: if self.has_import_star:
entry = self.declare_var(name, py_object_type, pos)
return entry
elif self.outer_scope is not None:
return self.outer_scope.declare_builtin(name, pos) return self.outer_scope.declare_builtin(name, pos)
else: else:
error(pos, "undeclared name not builtin: %s"%name) error(pos, "undeclared name not builtin: %s"%name)
......
...@@ -5,3 +5,8 @@ cdef void spam(): ...@@ -5,3 +5,8 @@ cdef void spam():
else: else:
k = j k = j
# new syntax
for 0 <= i < 10:
j = i
else:
j = k
cdef int* a
cdef object x
cdef int f(int i):
print i
return i
x[f(1)] = 3
a[f(1)] = 3
x[f(2)] += 4
a[f(2)] += 4
print x[1]
print a[1]
x[<object>f(1)] = 15
\ No newline at end of file
__doc__ = u"""
>>> test()
neg -1
pos 4294967294
neg
pos
neg
pos
"""
def test():
cdef long neg = -1
cdef unsigned long pos = -2 # will be a large positive number
print "neg", neg
print "pos", pos
D = { neg: 'neg', pos: 'pos' }
print D[<object>neg]
print D[<object>pos]
print D[neg]
print D[pos]
\ No newline at end of file
__doc__ = u"""
>>> f(5, 7)
29509034655744
>>> g(13, 4)
32
>>> h(56, 7)
105.0
"""
def f(a,b):
a += b
a *= b
a **= b
return a
def g(int a, int b):
a -= b
a /= b
a <<= b
return a
def h(double a, double b):
a /= b
a += b
a *= b
return a
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