Commit 7d26e739 authored by Robert Bradshaw's avatar Robert Bradshaw

Reworking of list conversion (needs to always analyse to a PyObject first to...

Reworking of list conversion (needs to always analyse to a PyObject first to play well with everything else.)
parent 5361eb62
...@@ -90,16 +90,19 @@ def close_listing_file(): ...@@ -90,16 +90,19 @@ def close_listing_file():
listing_file = None listing_file = None
def report_error(err): def report_error(err):
global num_errors if error_stack:
# See Main.py for why dual reporting occurs. Quick fix for now. error_stack[-1].append(err)
if err.reported: return else:
err.reported = True global num_errors
line = "%s\n" % err # See Main.py for why dual reporting occurs. Quick fix for now.
if listing_file: if err.reported: return
listing_file.write(line) err.reported = True
if echo_file: line = "%s\n" % err
echo_file.write(line) if listing_file:
num_errors = num_errors + 1 listing_file.write(line)
if echo_file:
echo_file.write(line)
num_errors = num_errors + 1
def error(position, message): def error(position, message):
#print "Errors.error:", repr(position), repr(message) ### #print "Errors.error:", repr(position), repr(message) ###
...@@ -120,3 +123,19 @@ def warning(position, message, level=0): ...@@ -120,3 +123,19 @@ def warning(position, message, level=0):
if echo_file: if echo_file:
echo_file.write(line) echo_file.write(line)
return warn return warn
# These functions can be used to momentarily suppress errors.
error_stack = []
def hold_errors():
error_stack.append([])
def release_errors(ignore=False):
held_errors = error_stack.pop()
if not ignore:
for err in held_errors:
report_error(err)
def held_errors():
return error_stack[-1]
...@@ -6,6 +6,7 @@ import operator ...@@ -6,6 +6,7 @@ import operator
from string import join from string import join
from Errors import error, warning, InternalError from Errors import error, warning, InternalError
from Errors import hold_errors, release_errors, held_errors, report_error
import StringEncoding import StringEncoding
import Naming import Naming
from Nodes import Node from Nodes import Node
...@@ -668,7 +669,10 @@ class IntNode(ConstNode): ...@@ -668,7 +669,10 @@ class IntNode(ConstNode):
type = PyrexTypes.c_long_type type = PyrexTypes.c_long_type
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
# Arrange for a Python version of the string to be pre-allocated if dst_type.is_numeric:
self.type = PyrexTypes.c_long_type
return self
# Arrange for a Python version of the number to be pre-allocated
# when coercing to a Python type. # when coercing to a Python type.
if dst_type.is_pyobject: if dst_type.is_pyobject:
self.entry = env.get_py_num(self.value, self.longness) self.entry = env.get_py_num(self.value, self.longness)
...@@ -730,6 +734,10 @@ class StringNode(ConstNode): ...@@ -730,6 +734,10 @@ class StringNode(ConstNode):
return sizeof_node.arg_type return sizeof_node.arg_type
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
if dst_type == PyrexTypes.c_char_ptr_type:
self.type = PyrexTypes.c_char_ptr_type
return self
if dst_type.is_int: if dst_type.is_int:
if not self.type.is_pyobject and len(self.entry.init) == 1: if not self.type.is_pyobject and len(self.entry.init) == 1:
return CharNode(self.pos, value=self.value) return CharNode(self.pos, value=self.value)
...@@ -752,7 +760,7 @@ class StringNode(ConstNode): ...@@ -752,7 +760,7 @@ class StringNode(ConstNode):
# but whose type is a Python type instead of a C type. # but whose type is a Python type instead of a C type.
entry = self.entry entry = self.entry
env.add_py_string(entry) env.add_py_string(entry)
return StringNode(self.pos, entry = entry, type = py_object_type) return StringNode(self.pos, value = self.value, entry = entry, type = py_object_type)
def calculate_result_code(self): def calculate_result_code(self):
if self.type.is_pyobject: if self.type.is_pyobject:
...@@ -1206,6 +1214,7 @@ class ImportNode(ExprNode): ...@@ -1206,6 +1214,7 @@ class ImportNode(ExprNode):
self.module_name = self.module_name.coerce_to_pyobject(env) self.module_name = self.module_name.coerce_to_pyobject(env)
if self.name_list: if self.name_list:
self.name_list.analyse_types(env) self.name_list.analyse_types(env)
self.name_list.coerce_to_pyobject(env)
self.type = py_object_type self.type = py_object_type
self.gil_check(env) self.gil_check(env)
self.is_temp = 1 self.is_temp = 1
...@@ -2655,30 +2664,38 @@ class TupleNode(SequenceNode): ...@@ -2655,30 +2664,38 @@ class TupleNode(SequenceNode):
class ListNode(SequenceNode): class ListNode(SequenceNode):
# List constructor. # List constructor.
# obj_conversion_errors [PyrexError] used internally
# orignial_args [ExprNode] used internally
gil_message = "Constructing Python list" gil_message = "Constructing Python list"
def analyse_expressions(self, env):
ExprNode.analyse_expressions(self, env)
self.coerce_to_pyobject(env)
def analyse_types(self, env): def analyse_types(self, env):
for arg in self.args: hold_errors()
arg.analyse_types(env) self.original_args = list(self.args)
self.is_temp = 1 SequenceNode.analyse_types(self, env)
self.type = PyrexTypes.unspecified_type self.type = list_type
self.obj_conversion_errors = held_errors()
release_errors(ignore=True)
def coerce_to(self, dst_type, env): def coerce_to(self, dst_type, env):
if dst_type.is_pyobject: if dst_type.is_pyobject:
self.gil_check(env) for err in self.obj_conversion_errors:
self.type = list_type report_error(err)
for i in range(len(self.args)): self.obj_conversion_errors = []
arg = self.args[i]
if not arg.type.is_pyobject:
self.args[i] = arg.coerce_to_pyobject(env)
if not self.type.subtype_of(dst_type): if not self.type.subtype_of(dst_type):
error(self.pos, "Cannot coerce list to type '%s'" % dst_type) error(self.pos, "Cannot coerce list to type '%s'" % dst_type)
elif dst_type.is_ptr: elif dst_type.is_ptr:
base_type = dst_type.base_type base_type = dst_type.base_type
self.type = dst_type self.type = dst_type
for i in range(len(self.args)): for i in range(len(self.original_args)):
arg = self.args[i] arg = self.args[i]
if isinstance(arg, CoerceToPyTypeNode):
arg = arg.arg
self.args[i] = arg.coerce_to(base_type, env) self.args[i] = arg.coerce_to(base_type, env)
elif dst_type.is_struct: elif dst_type.is_struct:
if len(self.args) > len(dst_type.scope.var_entries): if len(self.args) > len(dst_type.scope.var_entries):
...@@ -2686,7 +2703,9 @@ class ListNode(SequenceNode): ...@@ -2686,7 +2703,9 @@ class ListNode(SequenceNode):
else: else:
if len(self.args) < len(dst_type.scope.var_entries): if len(self.args) < len(dst_type.scope.var_entries):
warning(self.pos, "Too few members for '%s'" % dst_type, 1) warning(self.pos, "Too few members for '%s'" % dst_type, 1)
for i, (arg, member) in enumerate(zip(self.args, dst_type.scope.var_entries)): for i, (arg, member) in enumerate(zip(self.original_args, dst_type.scope.var_entries)):
if isinstance(arg, CoerceToPyTypeNode):
arg = arg.arg
self.args[i] = arg.coerce_to(member.type, env) self.args[i] = arg.coerce_to(member.type, env)
self.type = dst_type self.type = dst_type
else: else:
...@@ -2699,6 +2718,8 @@ class ListNode(SequenceNode): ...@@ -2699,6 +2718,8 @@ class ListNode(SequenceNode):
def generate_operation_code(self, code): def generate_operation_code(self, code):
if self.type.is_pyobject: if self.type.is_pyobject:
for err in self.obj_conversion_errors:
report_error(err)
code.putln("%s = PyList_New(%s); %s" % code.putln("%s = PyList_New(%s); %s" %
(self.result(), (self.result(),
len(self.args), len(self.args),
...@@ -2719,12 +2740,14 @@ class ListNode(SequenceNode): ...@@ -2719,12 +2740,14 @@ class ListNode(SequenceNode):
code.put(", ") code.put(", ")
code.putln(); code.putln();
code.putln("};") code.putln("};")
else: elif self.type.is_struct or 1:
for arg, member in zip(self.args, self.type.scope.var_entries): for arg, member in zip(self.args, self.type.scope.var_entries):
code.putln("%s.%s = %s;" % ( code.putln("%s.%s = %s;" % (
self.result(), self.result(),
member.cname, member.cname,
arg.result())) arg.result()))
else:
raise InternalError("List type never specified")
def generate_subexpr_disposal_code(self, code): def generate_subexpr_disposal_code(self, code):
# We call generate_post_assignment_code here instead # We call generate_post_assignment_code here instead
...@@ -4217,7 +4240,7 @@ class PyTypeTestNode(CoercionNode): ...@@ -4217,7 +4240,7 @@ class PyTypeTestNode(CoercionNode):
def generate_post_assignment_code(self, code): def generate_post_assignment_code(self, code):
self.arg.generate_post_assignment_code(code) self.arg.generate_post_assignment_code(code)
class CoerceToPyTypeNode(CoercionNode): class CoerceToPyTypeNode(CoercionNode):
# This node is used to convert a C data type # This node is used to convert a C data type
# to a Python object. # to a Python object.
...@@ -4402,7 +4425,7 @@ class PersistentNode(ExprNode): ...@@ -4402,7 +4425,7 @@ class PersistentNode(ExprNode):
self.result_ctype = self.arg.result_ctype self.result_ctype = self.arg.result_ctype
self.is_temp = 1 self.is_temp = 1
self.analyse_counter += 1 self.analyse_counter += 1
def calculate_result_code(self): def calculate_result_code(self):
return self.result() return self.result()
......
...@@ -162,12 +162,16 @@ class FinalOptimizePhase(Visitor.CythonTransform): ...@@ -162,12 +162,16 @@ class FinalOptimizePhase(Visitor.CythonTransform):
def visit_SimpleCallNode(self, node): def visit_SimpleCallNode(self, node):
self.visitchildren(node) self.visitchildren(node)
if node.function.type.is_cfunction and isinstance(node.function, ExprNodes.NameNode): if 0 and node.function.type.is_cfunction and isinstance(node.function, ExprNodes.NameNode):
if node.function.name == 'isinstance': if node.function.name == 'isinstance':
type_arg = node.args[1] type_arg = node.args[1]
if type_arg.type.is_builtin_type and type_arg.type.name == 'type': if type_arg.type.is_builtin_type and type_arg.type.name == 'type':
print type_arg.pos
object_module = self.context.find_module('python_object') object_module = self.context.find_module('python_object')
print object_module
print object_module.entries
node.function.entry = object_module.lookup('PyObject_TypeCheck') node.function.entry = object_module.lookup('PyObject_TypeCheck')
print node.function.entry
node.function.type = node.function.entry.type node.function.type = node.function.entry.type
PyTypeObjectPtr = PyrexTypes.CPtrType(object_module.lookup('PyTypeObject').type) PyTypeObjectPtr = PyrexTypes.CPtrType(object_module.lookup('PyTypeObject').type)
node.args[1] = ExprNodes.CastNode(node.args[1], PyTypeObjectPtr) node.args[1] = ExprNodes.CastNode(node.args[1], PyTypeObjectPtr)
......
cdef extern from "Python.h": cdef extern from "Python.h":
ctypedef void PyObject ctypedef void PyObject
ctypedef void PyTypeObject ctypedef void PyTypeObject
ctypedef struct FILE ctypedef struct FILE
##################################################################### #####################################################################
# 6.1 Object Protocol # 6.1 Object Protocol
......
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