Commit fde67796 authored by Dag Sverre Seljebotn's avatar Dag Sverre Seljebotn

merge

parents c84a953c 3bbefcb4
import re
from Cython.Compiler.Visitor import CythonTransform
from Cython.Compiler.Nodes import DefNode, CFuncDefNode
from Cython.Compiler.Errors import CompileError
from Cython.Compiler.StringEncoding import EncodedString
from Cython.Compiler import Options
from Cython.Compiler import PyrexTypes
class EmbedSignature(CythonTransform):
SPECIAL_METHOD_RE = re.compile(r'__\w+__')
class EmbedSignature(CythonTransform):
def __init__(self, context):
super(EmbedSignature, self).__init__(context)
self.denv = None # XXX
self.is_in_class = False
self.class_name = None
def _fmt_basic_c_type_modifiers(self, ctype):
longness = ctype.longness
modifiers = ''
if longness < 0:
modifiers = 'short '
elif longness > 0:
modifiers = 'long ' * longness
signed = ctype.signed
if signed == 0:
modifiers = 'unsigned ' + modifiers
elif signed == 2:
modifiers = 'signed ' + modifiers
return modifiers[:-1] # strip final space
def _fmt_arg_type(self, arg):
try:
base_type = arg.base_type
arg_type = base_type.name
except AttributeError:
return ''
if base_type.is_basic_c_type:
modifiers = self._fmt_basic_c_type_modifiers(base_type)
if modifiers:
arg_type = '%s %s' % (modifiers, arg_type)
return arg_type
def _fmt_arg_name(self, arg):
try:
return arg.declarator.name
except AttributeError:
return arg.declarator.base.name
def _fmt_arg_defv(self, arg):
if not arg.default:
return None
......@@ -63,14 +28,14 @@ class EmbedSignature(CythonTransform):
return '<???>'
def _fmt_arg(self, arg):
arg_type = self._fmt_arg_type(arg)
arg_name = self._fmt_arg_name(arg)
arg_defv = self._fmt_arg_defv(arg)
doc = arg_name
if arg_type:
doc = ('%s ' % arg_type) + doc
if arg_defv:
doc = doc + ('=%s' % arg_defv)
if arg.type is PyrexTypes.py_object_type or arg.is_self_arg:
doc = arg.name
else:
doc = arg.type.declaration_code(arg.name, for_display=1)
if arg.default:
arg_defv = self._fmt_arg_defv(arg)
if arg_defv:
doc = doc + ('=%s' % arg_defv)
return doc
def _fmt_arglist(self, args,
......@@ -89,13 +54,10 @@ class EmbedSignature(CythonTransform):
return arglist
def _fmt_ret_type(self, ret):
ret_type = ret.name
if ret_type is None:
return ''
modifiers = self._fmt_basic_c_type_modifiers(ret)
if modifiers:
ret_type = '%s %s' % (modifiers, ret_type)
return ret_type
if ret is PyrexTypes.py_object_type:
return None
else:
return ret.declaration_code("", for_display=1)
def _fmt_signature(self, cls_name, func_name, args,
npargs=0, pargs=None,
......@@ -128,9 +90,7 @@ class EmbedSignature(CythonTransform):
return super(EmbedSignature, self).__call__(node)
def visit_ClassDefNode(self, node):
oldincls = self.is_in_class
oldname = self.class_name
self.is_in_class = True
try:
# PyClassDefNode
self.class_name = node.name
......@@ -138,7 +98,6 @@ class EmbedSignature(CythonTransform):
# CClassDefNode
self.class_name = node.class_name
self.visitchildren(node)
self.is_in_class = oldincls
self.class_name = oldname
return node
......@@ -148,9 +107,7 @@ class EmbedSignature(CythonTransform):
signature = None
if type(node) is DefNode: # def FOO(...):
special_method = (self.is_in_class and \
self.SPECIAL_METHOD_RE.match(node.name))
if not special_method:
if not node.entry.is_special:
nkargs = getattr(node, 'num_kwonly_args', 0)
npargs = len(node.args) - nkargs
signature = self._fmt_signature(
......@@ -163,10 +120,12 @@ class EmbedSignature(CythonTransform):
signature = self._fmt_signature(
self.class_name, node.declarator.base.name,
node.declarator.args,
return_type=node.base_type)
return_type=node.return_type)
else: # should not fall here ...
assert False
if signature:
new_doc = self._embed_signature(signature, node.doc)
node.doc = EncodedString(new_doc) # XXX
new_doc = self._embed_signature(signature, node.entry.doc)
node.entry.doc = EncodedString(new_doc)
if hasattr(node, 'py_func') and node.py_func is not None:
node.py_func.entry.doc = EncodedString(new_doc)
return node
......@@ -30,6 +30,7 @@ builtin_function_table = [
('issubclass', "OO", "b", "PyObject_IsSubclass"),
('iter', "O", "O", "PyObject_GetIter"),
('len', "O", "Z", "PyObject_Length"),
('locals', "", "O", "__pyx_locals"),
#('map', "", "", ""),
#('max', "", "", ""),
#('min', "", "", ""),
......@@ -82,23 +83,34 @@ builtin_function_table = [
builtin_types_table = [
("type", "PyType_Type", []),
# ("str", "PyBytes_Type", []),
("bool", "PyBool_Type", []),
("int", "PyInt_Type", []),
("long", "PyLong_Type", []),
("float", "PyFloat_Type", []),
("complex", "PyComplex_Type", []),
("bytes", "PyBytes_Type", []),
("str", "PyString_Type", []),
("unicode", "PyUnicode_Type", []),
("file", "PyFile_Type", []),
# ("slice", "PySlice_Type", []),
# ("set", "PySet_Type", []),
("frozenset", "PyFrozenSet_Type", []),
("tuple", "PyTuple_Type", []),
("list", "PyList_Type", [("append", "OO", "i", "PyList_Append"),
("insert", "OiO", "i", "PyList_Insert"),
("sort", "O", "i", "PyList_Sort"),
("reverse","O", "i", "PyList_Reverse")]),
("dict", "PyDict_Type", [("items", "O", "O", "PyDict_Items"),
("keys", "O", "O", "PyDict_Keys"),
("values","O", "O", "PyDict_Values")]),
("set", "PySet_Type", []),
("frozenset", "PyFrozenSet_Type", []),
("slice", "PySlice_Type", []),
("file", "PyFile_Type", []),
]
builtin_structs_table = [
......
......@@ -190,13 +190,12 @@ class GlobalState(object):
self.init_cached_builtins_writer.putln("static int __Pyx_InitCachedBuiltins(void) {")
self.initwriter.enter_cfunc_scope()
self.initwriter.putln("").putln("static int __Pyx_InitGlobals(void) {")
self.initwriter.putln("")
self.initwriter.putln("static int __Pyx_InitGlobals(void) {")
(self.pystring_table
.putln("")
.putln("static __Pyx_StringTabEntry %s[] = {" %
self.pystring_table.putln("")
self.pystring_table.putln("static __Pyx_StringTabEntry %s[] = {" %
Naming.stringtab_cname)
)
#
# Global constants, interned objects, etc.
......@@ -208,7 +207,8 @@ class GlobalState(object):
# This is called when it is known that no more global declarations will
# declared (but can be called before or after insert_XXX).
if self.pystring_table_needed:
self.pystring_table.putln("{0, 0, 0, 0, 0, 0}").putln("};")
self.pystring_table.putln("{0, 0, 0, 0, 0, 0}")
self.pystring_table.putln("};")
import Nodes
self.use_utility_code(Nodes.init_string_tab_utility_code)
self.initwriter.putln(
......@@ -217,21 +217,19 @@ class GlobalState(object):
self.initwriter.error_goto(self.module_pos)))
if Options.cache_builtins:
(self.init_cached_builtins_writer
.putln("return 0;")
.put_label(self.init_cached_builtins_writer.error_label)
.putln("return -1;")
.putln("}")
.exit_cfunc_scope()
)
(self.initwriter
.putln("return 0;")
.put_label(self.initwriter.error_label)
.putln("return -1;")
.putln("}")
.exit_cfunc_scope()
)
w = self.init_cached_builtins_writer
w.putln("return 0;")
w.put_label(w.error_label)
w.putln("return -1;")
w.putln("}")
w.exit_cfunc_scope()
w = self.initwriter
w.putln("return 0;")
w.put_label(w.error_label)
w.putln("return -1;")
w.putln("}")
w.exit_cfunc_scope()
def insert_initcode_into(self, code):
if self.pystring_table_needed:
......@@ -526,7 +524,6 @@ class CCodeWriter(object):
self.put(code)
self.write("\n");
self.bol = 1
return self
def emit_marker(self):
self.write("\n");
......@@ -534,7 +531,6 @@ class CCodeWriter(object):
self.write("/* %s */\n" % self.marker[1])
self.last_marker_line = self.marker[0]
self.marker = None
return self
def put_safe(self, code):
# put code, but ignore {}
......@@ -557,25 +553,20 @@ class CCodeWriter(object):
self.level += dl
elif fix_indent:
self.level += 1
return self
def increase_indent(self):
self.level = self.level + 1
return self
def decrease_indent(self):
self.level = self.level - 1
return self
def begin_block(self):
self.putln("{")
self.increase_indent()
return self
def end_block(self):
self.decrease_indent()
self.putln("}")
return self
def indent(self):
self.write(" " * self.level)
......@@ -604,12 +595,10 @@ class CCodeWriter(object):
def put_label(self, lbl):
if lbl in self.funcstate.labels_used:
self.putln("%s:;" % lbl)
return self
def put_goto(self, lbl):
self.funcstate.use_label(lbl)
self.putln("goto %s;" % lbl)
return self
def put_var_declarations(self, entries, static = 0, dll_linkage = None,
definition = True):
......
......@@ -290,6 +290,11 @@ class ExprNode(Node):
# If this node can be interpreted as a reference to a
# cimported module, return its scope, else None.
return None
def analyse_as_type(self, env):
# If this node can be interpreted as a reference to a
# type, return that type, else None.
return None
def analyse_as_extension_type(self, env):
# If this node can be interpreted as a reference to an
......@@ -773,6 +778,15 @@ class StringNode(ConstNode):
def analyse_types(self, env):
self.entry = env.add_string_const(self.value)
def analyse_as_type(self, env):
from TreeFragment import TreeFragment
pos = (self.pos[0], self.pos[1], self.pos[2]-7)
declaration = TreeFragment(u"sizeof(%s)" % self.value, name=pos[0].filename, initial_pos=pos)
sizeof_node = declaration.root.stats[0].expr
sizeof_node.analyse_types(env)
if isinstance(sizeof_node, SizeofTypeNode):
return sizeof_node.arg_type
def coerce_to(self, dst_type, env):
if dst_type.is_int:
......@@ -944,6 +958,17 @@ class NameNode(AtomicExprNode):
if entry and entry.as_module:
return entry.as_module
return None
def analyse_as_type(self, env):
if self.name in PyrexTypes.rank_to_type_name:
return PyrexTypes.simple_c_type(1, 0, self.name)
entry = self.entry
if not entry:
entry = env.lookup(self.name)
if entry and entry.is_type:
return entry.type
else:
return None
def analyse_as_extension_type(self, env):
# Try to interpret this as a reference to an extension type.
......@@ -1427,6 +1452,12 @@ class IndexNode(ExprNode):
def analyse_target_declaration(self, env):
pass
def analyse_as_type(self, env):
base_type = self.base.analyse_as_type(env)
if base_type and not base_type.is_pyobject:
return PyrexTypes.CArrayType(base_type, int(self.index.compile_time_value(env)))
return None
def analyse_types(self, env):
self.analyse_base_and_index_types(env, getting = 1)
......@@ -2243,6 +2274,14 @@ class AttributeNode(ExprNode):
self.mutate_into_name_node(env, ubcm_entry, None)
return 1
return 0
def analyse_as_type(self, env):
module_scope = self.obj.analyse_as_module(env)
if module_scope:
entry = module_scope.lookup_here(self.attribute)
if entry and entry.is_type:
return entry.type
return None
def analyse_as_extension_type(self, env):
# Try to interpret this as a reference to an extension type
......@@ -2800,6 +2839,9 @@ class DictItemNode(ExprNode):
def generate_disposal_code(self, code):
self.key.generate_disposal_code(code)
self.value.generate_disposal_code(code)
def __iter__(self):
return iter([self.key, self.value])
class ClassNode(ExprNode):
......@@ -3168,6 +3210,8 @@ class TypecastNode(ExprNode):
class SizeofNode(ExprNode):
# Abstract base class for sizeof(x) expression nodes.
type = PyrexTypes.c_int_type
def check_const(self):
pass
......@@ -3183,11 +3227,12 @@ class SizeofTypeNode(SizeofNode):
# declarator CDeclaratorNode
subexprs = []
arg_type = None
def analyse_types(self, env):
# we may have incorrectly interpreted a dotted name as a type rather than an attribute
# this could be better handled by more uniformly treating types as runtime-available objects
if self.base_type.module_path:
if 0 and self.base_type.module_path:
path = self.base_type.module_path
obj = env.lookup(path[0])
if obj.as_module is None:
......@@ -3199,16 +3244,20 @@ class SizeofTypeNode(SizeofNode):
self.__class__ = SizeofVarNode
self.analyse_types(env)
return
base_type = self.base_type.analyse(env)
_, arg_type = self.declarator.analyse(base_type, env)
self.arg_type = arg_type
if self.arg_type is None:
base_type = self.base_type.analyse(env)
_, arg_type = self.declarator.analyse(base_type, env)
self.arg_type = arg_type
self.check_type()
def check_type(self):
arg_type = self.arg_type
if arg_type.is_pyobject and not arg_type.is_extension_type:
error(self.pos, "Cannot take sizeof Python object")
elif arg_type.is_void:
error(self.pos, "Cannot take sizeof void")
elif not arg_type.is_complete():
error(self.pos, "Cannot take sizeof incomplete type '%s'" % arg_type)
self.type = PyrexTypes.c_int_type
def calculate_result_code(self):
if self.arg_type.is_extension_type:
......@@ -3228,8 +3277,15 @@ class SizeofVarNode(SizeofNode):
subexprs = ['operand']
def analyse_types(self, env):
self.operand.analyse_types(env)
self.type = PyrexTypes.c_int_type
# We may actually be looking at a type rather than a variable...
# If we are, traditional analysis would fail...
operand_as_type = self.operand.analyse_as_type(env)
if operand_as_type:
self.arg_type = operand_as_type
self.__class__ = SizeofTypeNode
self.check_type()
else:
self.operand.analyse_types(env)
def calculate_result_code(self):
return "(sizeof(%s))" % self.operand.result()
......@@ -3475,22 +3531,27 @@ class FloorDivNode(NumBinopNode):
self.operand2.result())
class ModNode(IntBinopNode):
class ModNode(NumBinopNode):
# '%' operator.
def is_py_operation(self):
return (self.operand1.type.is_string
or self.operand2.type.is_string
or IntBinopNode.is_py_operation(self))
or NumBinopNode.is_py_operation(self))
def calculate_result_code(self):
if self.operand1.type.is_float or self.operand2.type.is_float:
return "fmod(%s, %s)" % (
self.operand1.result(),
self.operand2.result())
else:
return "(%s %% %s)" % (
self.operand1.result(),
self.operand2.result())
class PowNode(NumBinopNode):
# '**' operator.
def analyse_types(self, env):
env.pow_function_used = 1
NumBinopNode.analyse_types(self, env)
def compute_c_result_type(self, type1, type2):
if self.c_types_okay(type1, type2):
return PyrexTypes.c_double_type
......
......@@ -79,7 +79,7 @@ class Context:
from ParseTreeTransforms import WithTransform, NormalizeTree, PostParse, PxdPostParse
from ParseTreeTransforms import AnalyseDeclarationsTransform, AnalyseExpressionsTransform
from ParseTreeTransforms import CreateClosureClasses, MarkClosureVisitor, DecoratorTransform
from ParseTreeTransforms import InterpretCompilerDirectives
from ParseTreeTransforms import InterpretCompilerDirectives, TransformBuiltinMethods
from AutoDocTransforms import EmbedSignature
from Optimize import FlattenInListTransform, SwitchTransform, FinalOptimizePhase
from Buffer import IntroduceBufferAuxiliaryVars
......@@ -97,11 +97,12 @@ class Context:
PostParse(self),
_specific_post_parse,
InterpretCompilerDirectives(self, self.pragma_overrides),
EmbedSignature(self),
FlattenInListTransform(),
WithTransform(self),
DecoratorTransform(self),
AnalyseDeclarationsTransform(self),
EmbedSignature(self),
TransformBuiltinMethods(self),
IntroduceBufferAuxiliaryVars(self),
_check_c_classes,
AnalyseExpressionsTransform(self),
......
......@@ -411,8 +411,10 @@ class CNameDeclaratorNode(CDeclaratorNode):
error(self.pos, "Missing argument name")
elif base_type.is_void:
error(self.pos, "Use spam() rather than spam(void) to declare a function with no arguments.")
self.name = base_type.declaration_code("", for_display=1, pyrex=1)
base_type = py_object_type
else:
print "here"
self.name = base_type.declaration_code("", for_display=1, pyrex=1)
base_type = py_object_type
self.type = base_type
return self, base_type
......@@ -570,7 +572,19 @@ class CArgDeclNode(Node):
def analyse(self, env, nonempty = 0):
#print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
base_type = self.base_type.analyse(env)
# The parser may missinterpret names as types...
# We fix that here.
if isinstance(self.declarator, CNameDeclaratorNode) and self.declarator.name == '':
if nonempty:
self.declarator.name = self.base_type.name
self.base_type.name = None
self.base_type.is_basic_c_type = False
could_be_name = True
else:
could_be_name = False
base_type = self.base_type.analyse(env, could_be_name = could_be_name)
if self.base_type.arg_name:
self.declarator.name = self.base_type.arg_name
return self.declarator.analyse(base_type, env, nonempty = nonempty)
def annotate(self, code):
......@@ -597,8 +611,9 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
# is_self_arg boolean Is self argument of C method
child_attrs = []
arg_name = None # in case the argument name was interpreted as a type
def analyse(self, env):
def analyse(self, env, could_be_name = False):
# Return type descriptor.
#print "CSimpleBaseTypeNode.analyse: is_self_arg =", self.is_self_arg ###
type = None
......@@ -615,13 +630,22 @@ class CSimpleBaseTypeNode(CBaseTypeNode):
else:
type = py_object_type
else:
scope = env.find_imported_module(self.module_path, self.pos)
if self.module_path:
scope = env.find_imported_module(self.module_path, self.pos)
else:
scope = env
if scope:
if scope.is_c_class_scope:
scope = scope.global_scope()
entry = scope.find(self.name, self.pos)
entry = scope.lookup(self.name)
if entry and entry.is_type:
type = entry.type
elif could_be_name:
if self.is_self_arg and env.is_c_class_scope:
type = env.parent_type
else:
type = py_object_type
self.arg_name = self.name
else:
error(self.pos, "'%s' is not a type identifier" % self.name)
if type:
......@@ -644,7 +668,7 @@ class CBufferAccessTypeNode(CBaseTypeNode):
dtype_node = None
def analyse(self, env):
def analyse(self, env, could_be_name = False):
base_type = self.base_type_node.analyse(env)
if base_type.is_error: return base_type
import Buffer
......@@ -665,8 +689,8 @@ class CComplexBaseTypeNode(CBaseTypeNode):
child_attrs = ["base_type", "declarator"]
def analyse(self, env):
base = self.base_type.analyse(env)
def analyse(self, env, could_be_name = False):
base = self.base_type.analyse(env, could_be_name)
_, type = self.declarator.analyse(base, env)
return type
......@@ -1142,11 +1166,16 @@ class CFuncDefNode(FuncDefNode):
# overridable whether or not this is a cpdef function
child_attrs = ["base_type", "declarator", "body", "py_func"]
def unqualified_name(self):
return self.entry.name
def analyse_declarations(self, env):
if 'locals' in env.directives:
directive_locals = env.directives['locals']
else:
directive_locals = {}
self.directive_locals = directive_locals
base_type = self.base_type.analyse(env)
# The 2 here is because we need both function and argument names.
name_declarator, type = self.declarator.analyse(base_type, env, nonempty = 2 * (self.body is not None))
......@@ -1418,11 +1447,27 @@ class DefNode(FuncDefNode):
entry = None
def analyse_declarations(self, env):
if 'locals' in env.directives:
directive_locals = env.directives['locals']
else:
directive_locals = {}
self.directive_locals = directive_locals
for arg in self.args:
base_type = arg.base_type.analyse(env)
name_declarator, type = \
arg.declarator.analyse(base_type, env)
arg.name = name_declarator.name
if arg.name in directive_locals:
type_node = directive_locals[arg.name]
other_type = type_node.analyse_as_type(env)
if other_type is None:
error(type_node.pos, "Not a type")
elif (type is not PyrexTypes.py_object_type
and not type.same_as(other_type)):
error(arg.base_type.pos, "Signature does not agree with previous declaration")
error(type_node.pos, "Previous declaration here")
else:
type = other_type
if name_declarator.cname:
error(self.pos,
"Python function argument cannot have C name specification")
......
......@@ -58,13 +58,15 @@ c_line_in_traceback = 1
option_types = {
'boundscheck' : bool,
'nonecheck' : bool,
'embedsignature' : bool
'embedsignature' : bool,
'locals' : dict,
}
option_defaults = {
'boundscheck' : True,
'nonecheck' : False,
'embedsignature' : False,
'locals' : {}
}
def parse_option_value(name, value):
......
......@@ -282,6 +282,7 @@ class InterpretCompilerDirectives(CythonTransform):
self.options = options
node.directives = options
self.visitchildren(node)
node.cython_module_names = self.cython_module_names
return node
# Track cimports of the cython module.
......@@ -308,6 +309,14 @@ class InterpretCompilerDirectives(CythonTransform):
newimp.append((pos, name, as_name, kind))
node.imported_names = newimpo
return node
def visit_SingleAssignmentNode(self, node):
if (isinstance(node.rhs, ImportNode) and
node.rhs.module_name.value == u'cython'):
self.cython_module_names.add(node.lhs.name)
else:
self.visitchildren(node)
return node
def visit_Node(self, node):
self.visitchildren(node)
......@@ -318,7 +327,7 @@ class InterpretCompilerDirectives(CythonTransform):
# decorator), returns (optionname, value).
# Otherwise, returns None
optname = None
if isinstance(node, SimpleCallNode):
if isinstance(node, CallNode):
if (isinstance(node.function, AttributeNode) and
isinstance(node.function.obj, NameNode) and
node.function.obj.name in self.cython_module_names):
......@@ -330,12 +339,25 @@ class InterpretCompilerDirectives(CythonTransform):
if optname:
optiontype = Options.option_types.get(optname)
if optiontype:
args = node.args
if isinstance(node, SimpleCallNode):
args = node.args
kwds = None
else:
if node.starstar_arg or not isinstance(node.positional_args, TupleNode):
raise PostParseError(dec.function.pos,
'Compile-time keyword arguments must be explicit.' % optname)
args = node.positional_args.args
kwds = node.keyword_args
if optiontype is bool:
if len(args) != 1 or not isinstance(args[0], BoolNode):
if kwds is not None or len(args) != 1 or not isinstance(args[0], BoolNode):
raise PostParseError(dec.function.pos,
'The %s option takes one compile-time boolean argument' % optname)
return (optname, args[0].value)
elif optiontype is dict:
if len(args) != 0:
raise PostParseError(dec.function.pos,
'The %s option takes no prepositional arguments' % optname)
return optname, dict([(key.value, value) for key, value in kwds.key_value_pairs])
else:
assert False
......@@ -367,7 +389,7 @@ class InterpretCompilerDirectives(CythonTransform):
else:
realdecs.append(dec)
node.decorators = realdecs
if options:
optdict = {}
options.reverse() # Decorators coming first take precedence
......@@ -499,12 +521,19 @@ property NAME:
lenv = node.create_local_scope(self.env_stack[-1])
node.body.analyse_control_flow(lenv) # this will be totally refactored
node.declare_arguments(lenv)
for var, type_node in node.directive_locals.items():
if not lenv.lookup_here(var): # don't redeclare args
type = type_node.analyse_as_type(lenv)
if type:
lenv.declare_var(var, type, type_node.pos)
else:
error(type_node.pos, "Not a type")
node.body.analyse_declarations(lenv)
self.env_stack.append(lenv)
self.visitchildren(node)
self.env_stack.pop()
return node
# Some nodes are no longer needed after declaration
# analysis and can be dropped. The analysis was performed
# on these nodes in a seperate recursive process from the
......@@ -534,6 +563,7 @@ property NAME:
return property
class AnalyseExpressionsTransform(CythonTransform):
def visit_ModuleNode(self, node):
node.body.analyse_expressions(node.scope)
self.visitchildren(node)
......@@ -591,3 +621,78 @@ class CreateClosureClasses(CythonTransform):
return node
class EnvTransform(CythonTransform):
"""
This transformation keeps a stack of the environments.
"""
def __call__(self, root):
self.env_stack = [root.scope]
return super(EnvTransform, self).__call__(root)
def visit_FuncDefNode(self, node):
self.env_stack.append(node.local_scope)
self.visitchildren(node)
self.env_stack.pop()
return node
class TransformBuiltinMethods(EnvTransform):
def cython_attribute(self, node):
if (isinstance(node, AttributeNode) and
isinstance(node.obj, NameNode) and
node.obj.name in self.cython_module_names):
return node.attribute
def visit_ModuleNode(self, node):
self.cython_module_names = node.cython_module_names
self.visitchildren(node)
return node
def visit_AttributeNode(self, node):
attribute = self.cython_attribute(node)
if attribute:
if attribute == u'compiled':
node = BoolNode(node.pos, value=True)
else:
error(node.function.pos, u"'%s' not a valid cython attribute" % function)
return node
def visit_SimpleCallNode(self, node):
# locals
if isinstance(node.function, ExprNodes.NameNode):
if node.function.name == 'locals':
pos = node.pos
lenv = self.env_stack[-1]
items = [ExprNodes.DictItemNode(pos,
key=ExprNodes.IdentifierStringNode(pos, value=var),
value=ExprNodes.NameNode(pos, name=var)) for var in lenv.entries]
return ExprNodes.DictNode(pos, key_value_pairs=items)
# cython.foo
function = self.cython_attribute(node.function)
if function:
if function == u'cast':
if len(node.args) != 2:
error(node.function.pos, u"cast takes exactly two arguments" % function)
else:
type = node.args[0].analyse_as_type(self.env_stack[-1])
if type:
node = TypecastNode(node.function.pos, type=type, operand=node.args[1])
else:
error(node.args[0].pos, "Not a type")
elif function == u'sizeof':
if len(node.args) != 1:
error(node.function.pos, u"sizeof takes exactly one argument" % function)
else:
type = node.args[0].analyse_as_type(self.env_stack[-1])
if type:
node = SizeofTypeNode(node.function.pos, arg_type=type)
else:
node = SizeofVarNode(node.function.pos, operand=node.args[0])
else:
error(node.function.pos, u"'%s' not a valid cython language construct" % function)
self.visitchildren(node)
return node
......@@ -250,14 +250,17 @@ def p_sizeof(s):
pos = s.position()
s.next()
s.expect('(')
if looking_at_type(s) or looking_at_dotted_name(s):
# Here we decide if we are looking at an expression or type
# If it is actually a type, but parsable as an expression,
# we treat it as an expression here.
if looking_at_expr(s):
operand = p_simple_expr(s)
node = ExprNodes.SizeofVarNode(pos, operand = operand)
else:
base_type = p_c_base_type(s)
declarator = p_c_declarator(s, empty = 1)
node = ExprNodes.SizeofTypeNode(pos,
base_type = base_type, declarator = declarator)
else:
operand = p_simple_expr(s)
node = ExprNodes.SizeofVarNode(pos, operand = operand)
s.expect(')')
return node
......@@ -1028,9 +1031,6 @@ def p_from_import_statement(s, first_statement = 0):
s.context.future_directives.add(directive)
return Nodes.PassStatNode(pos)
elif kind == 'cimport':
for (name_pos, name, as_name, kind) in imported_names:
local_name = as_name or name
s.add_type_name(local_name)
return Nodes.FromCImportStatNode(pos,
module_name = dotted_name,
imported_names = imported_names)
......@@ -1604,7 +1604,7 @@ def p_c_complex_base_type(s):
base_type = base_type, declarator = declarator)
def p_c_simple_base_type(s, self_flag, nonempty):
#print "p_c_simple_base_type: self_flag =", self_flag
#print "p_c_simple_base_type: self_flag =", self_flag, nonempty
is_basic = 0
signed = 1
longness = 0
......@@ -1619,12 +1619,19 @@ def p_c_simple_base_type(s, self_flag, nonempty):
s.next()
else:
name = 'int'
elif s.looking_at_type_name():
elif looking_at_dotted_name(s):
#print "p_c_simple_base_type: looking_at_type_name at", s.position()
name = s.systring
s.next()
while s.sy == '.':
module_path.append(name)
s.next()
name = p_ident(s)
else:
name = s.systring
s.next()
if nonempty and s.sy != 'IDENT':
# Make sure this is not a declaration of a variable or
# function with the same name as a type.
# Make sure this is not a declaration of a variable or function.
if s.sy == '(':
s.next()
if s.sy == '*' or s.sy == '**':
......@@ -1636,18 +1643,7 @@ def p_c_simple_base_type(s, self_flag, nonempty):
elif s.sy not in ('*', '**', '['):
s.put_back('IDENT', name)
name = None
elif looking_at_dotted_name(s):
#print "p_c_simple_base_type: looking_at_type_name at", s.position()
name = s.systring
s.next()
while s.sy == '.':
module_path.append(name)
s.next()
name = p_ident(s)
else:
#print "p_c_simple_base_type: not looking at type at", s.position()
name = None
type_node = Nodes.CSimpleBaseTypeNode(pos,
name = name, module_path = module_path,
is_basic_c_type = is_basic, signed = signed,
......@@ -1687,8 +1683,44 @@ def p_buffer_access(s, base_type_node):
return result
def looking_at_type(s):
return looking_at_base_type(s) or s.looking_at_type_name()
def looking_at_name(s):
return s.sy == 'IDENT' and not s.systring in calling_convention_words
def looking_at_expr(s):
if s.systring in base_type_start_words:
return False
elif s.sy == 'IDENT':
is_type = False
name = s.systring
dotted_path = []
s.next()
while s.sy == '.':
s.next()
dotted_path.append(s.systring)
s.expect('IDENT')
saved = s.sy, s.systring
if s.sy == 'IDENT':
is_type = True
elif s.sy == '*' or s.sy == '**':
s.next()
is_type = s.sy == ')'
s.put_back(*saved)
elif s.sy == '(':
s.next()
is_type = s.sy == '*'
s.put_back(*saved)
elif s.sy == '[':
s.next()
is_type = s.sy == ']'
s.put_back(*saved)
dotted_path.reverse()
for p in dotted_path:
s.put_back('IDENT', p)
s.put_back('.', '.')
s.put_back('IDENT', name)
return not is_type
else:
return True
def looking_at_base_type(s):
#print "looking_at_base_type?", s.sy, s.systring, s.position()
......@@ -1703,7 +1735,7 @@ def looking_at_dotted_name(s):
return result
else:
return 0
basic_c_type_names = ("void", "char", "int", "float", "double", "Py_ssize_t", "bint")
sign_and_longness_words = ("short", "long", "signed", "unsigned")
......@@ -1744,7 +1776,7 @@ def p_c_declarator(s, ctx = Ctx(), empty = 0, is_type = 0, cmethod_flag = 0,
pos = s.position()
if s.sy == '(':
s.next()
if s.sy == ')' or looking_at_type(s):
if s.sy == ')' or looking_at_name(s):
base = Nodes.CNameDeclaratorNode(pos, name = EncodedString(u""), cname = None)
result = p_c_func_declarator(s, pos, ctx, base, cmethod_flag)
else:
......@@ -1816,8 +1848,6 @@ def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
rhs = None
if s.sy == 'IDENT':
name = EncodedString(s.systring)
if is_type:
s.add_type_name(name)
if empty:
error(s.position(), "Declarator should be empty")
s.next()
......@@ -2002,7 +2032,6 @@ def p_c_enum_definition(s, pos, ctx):
if s.sy == 'IDENT':
name = s.systring
s.next()
s.add_type_name(name)
cname = p_opt_cname(s)
else:
name = None
......@@ -2052,7 +2081,6 @@ def p_c_struct_or_union_definition(s, pos, ctx):
s.next()
name = p_ident(s)
cname = p_opt_cname(s)
s.add_type_name(name)
attributes = None
if s.sy == ':':
s.next()
......@@ -2149,6 +2177,8 @@ def p_ctypedef_statement(s, ctx):
return p_c_struct_or_union_definition(s, pos, ctx)
else:
base_type = p_c_base_type(s, nonempty = 1)
if base_type.name is None:
s.error("Syntax error in ctypedef statement")
declarator = p_c_declarator(s, ctx, is_type = 1, nonempty = 1)
s.expect_newline("Syntax error in ctypedef statement")
return Nodes.CTypeDefNode(
......@@ -2244,7 +2274,6 @@ def p_c_class_definition(s, pos, ctx):
as_name = p_ident(s)
else:
as_name = class_name
s.add_type_name(as_name)
objstruct_name = None
typeobj_name = None
base_class_module = None
......@@ -2345,8 +2374,6 @@ def p_doc_string(s):
return None
def p_code(s, level=None):
s.add_type_name("object")
s.add_type_name("Py_buffer")
body = p_statement_list(s, Ctx(level = level), first_statement = 1)
if s.sy != 'EOF':
s.error("Syntax error in statement [%s,%s]" % (
......@@ -2371,8 +2398,6 @@ def p_compiler_directive_comments(s):
return result
def p_module(s, pxd, full_module_name):
s.add_type_name("object")
s.add_type_name("Py_buffer")
pos = s.position()
doc = p_doc_string(s)
if pxd:
......
......@@ -280,7 +280,6 @@ class BuiltinObjectType(PyObjectType):
return "<%s>"% self.cname
def assignable_from(self, src_type):
if isinstance(src_type, BuiltinObjectType):
return src_type.name == self.name
else:
......@@ -473,6 +472,8 @@ class CNumericType(CType):
def declaration_code(self, entity_code,
for_display = 0, dll_linkage = None, pyrex = 0):
base = public_decl(self.sign_and_name(), dll_linkage)
if for_display and self.is_longlong:
base = base.replace('PY_LONG_LONG', 'long long')
return self.base_declaration_code(base, entity_code)
......@@ -557,7 +558,7 @@ class CULongType(CUIntType):
from_py_function = "PyInt_AsUnsignedLongMask"
class CLongLongType(CUIntType):
class CLongLongType(CIntType):
is_longlong = 1
to_py_function = "PyLong_FromLongLong"
......@@ -1184,6 +1185,9 @@ modifiers_and_name_to_type = {
(2, 1, "int"): c_slong_type,
(2, 2, "int"): c_slonglong_type,
(2, 0, "Py_ssize_t"): c_py_ssize_t_type,
(1, 0, "long"): c_long_type,
(1, 0, "bint"): c_bint_type,
}
def widest_numeric_type(type1, type2):
......@@ -1220,6 +1224,19 @@ def c_ptr_type(base_type):
return c_char_ptr_type
else:
return CPtrType(base_type)
def Node_to_type(node, env):
from ExprNodes import NameNode, AttributeNode, StringNode, error
if isinstance(node, StringNode):
node = NameNode(node.pos, name=node.value)
if isinstance(node, NameNode) and node.name in rank_to_type_name:
return simple_c_type(1, 0, node.name)
elif isinstance(node, (AttributeNode, NameNode)):
node.analyze_types(env)
if not node.entry.is_type:
pass
else:
error(node.pos, "Bad type")
def public_decl(base, dll_linkage):
if dll_linkage:
......
......@@ -282,7 +282,6 @@ class StringSourceDescriptor(SourceDescriptor):
class PyrexScanner(Scanner):
# context Context Compilation context
# type_names set Identifiers to be treated as type names
# included_files [string] Files included with 'include' statement
# compile_time_env dict Environment for conditional compilation
# compile_time_eval boolean In a true conditional compilation context
......@@ -290,18 +289,16 @@ class PyrexScanner(Scanner):
resword_dict = build_resword_dict()
def __init__(self, file, filename, parent_scanner = None,
scope = None, context = None, source_encoding=None, parse_comments=True):
Scanner.__init__(self, get_lexicon(), file, filename)
scope = None, context = None, source_encoding=None, parse_comments=True, initial_pos=None):
Scanner.__init__(self, get_lexicon(), file, filename, initial_pos)
if parent_scanner:
self.context = parent_scanner.context
self.type_names = parent_scanner.type_names
self.included_files = parent_scanner.included_files
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 = scope.type_names
self.included_files = scope.included_files
self.compile_time_env = initial_compile_time_env()
self.compile_time_eval = 1
......@@ -431,12 +428,6 @@ class PyrexScanner(Scanner):
# This method should be added to Plex
self.queue.insert(0, (token, value))
def add_type_name(self, name):
self.type_names[name] = 1
def looking_at_type_name(self):
return self.sy == 'IDENT' and self.systring in self.type_names
def error(self, message, pos = None, fatal = True):
if pos is None:
pos = self.position()
......
......@@ -167,7 +167,6 @@ class Scope:
# temp_counter integer Counter for naming temp vars
# cname_to_entry {string : Entry} Temp cname to entry mapping
# int_to_entry {int : Entry} Temp cname to entry mapping
# pow_function_used boolean The C pow() function is used
# return_type PyrexType or None Return type of function owning scope
# is_py_class_scope boolean Is a Python class scope
# is_c_class_scope boolean Is an extension type scope
......@@ -221,7 +220,6 @@ class Scope:
#self.pending_temp_entries = [] # TEMPORARY
self.temp_counter = 1
self.cname_to_entry = {}
self.pow_function_used = 0
self.string_to_entry = {}
self.identifier_to_entry = {}
self.num_to_entry = {}
......@@ -315,6 +313,7 @@ class Scope:
entry.is_type = 1
if defining:
self.type_entries.append(entry)
# here we would set as_variable to an object representing this type
return entry
def declare_typedef(self, name, base_type, pos, cname = None,
......@@ -637,8 +636,6 @@ class Scope:
def generate_library_function_declarations(self, code):
# Generate extern decls for C library funcs used.
#if self.pow_function_used:
# code.putln("%s double pow(double, double);" % Naming.extern_c_macro)
pass
def defines_any(self, names):
......@@ -722,21 +719,27 @@ class BuiltinScope(Scope):
def builtin_scope(self):
return self
builtin_entries = {
"type": ["((PyObject*)&PyType_Type)", py_object_type],
"bool": ["((PyObject*)&PyBool_Type)", py_object_type],
"int": ["((PyObject*)&PyInt_Type)", py_object_type],
"long": ["((PyObject*)&PyLong_Type)", py_object_type],
"float": ["((PyObject*)&PyFloat_Type)", py_object_type],
"str": ["((PyObject*)&PyBytes_Type)", py_object_type],
"complex":["((PyObject*)&PyComplex_Type)", py_object_type],
"bytes": ["((PyObject*)&PyBytes_Type)", py_object_type],
"str": ["((PyObject*)&PyString_Type)", py_object_type],
"unicode":["((PyObject*)&PyUnicode_Type)", py_object_type],
"tuple": ["((PyObject*)&PyTuple_Type)", py_object_type],
"list": ["((PyObject*)&PyList_Type)", py_object_type],
"dict": ["((PyObject*)&PyDict_Type)", py_object_type],
"set": ["((PyObject*)&PySet_Type)", py_object_type],
"frozenset": ["((PyObject*)&PyFrozenSet_Type)", py_object_type],
"type": ["((PyObject*)&PyType_Type)", py_object_type],
"slice": ["((PyObject*)&PySlice_Type)", py_object_type],
"file": ["((PyObject*)&PyFile_Type)", py_object_type],
......
......@@ -29,7 +29,7 @@ class StringParseContext(Main.Context):
raise AssertionError("Not yet supporting any cimports/includes from string code snippets")
return ModuleScope(module_name, parent_module = None, context = self)
def parse_from_strings(name, code, pxds={}, level=None):
def parse_from_strings(name, code, pxds={}, level=None, initial_pos=None):
"""
Utility method to parse a (unicode) string of code. This is mostly
used for internal Cython compiler purposes (creating code snippets
......@@ -47,7 +47,8 @@ def parse_from_strings(name, code, pxds={}, level=None):
encoding = "UTF-8"
module_name = name
initial_pos = (name, 1, 0)
if initial_pos is None:
initial_pos = (name, 1, 0)
code_source = StringSourceDescriptor(name, code)
context = StringParseContext([], name)
......@@ -56,7 +57,7 @@ def parse_from_strings(name, code, pxds={}, level=None):
buf = StringIO(code.encode(encoding))
scanner = PyrexScanner(buf, code_source, source_encoding = encoding,
scope = scope, context = context)
scope = scope, context = context, initial_pos = initial_pos)
if level is None:
tree = Parsing.p_module(scanner, 0, module_name)
else:
......@@ -181,7 +182,7 @@ def strip_common_indent(lines):
return lines
class TreeFragment(object):
def __init__(self, code, name="(tree fragment)", pxds={}, temps=[], pipeline=[], level=None):
def __init__(self, code, name="(tree fragment)", pxds={}, temps=[], pipeline=[], level=None, initial_pos=None):
if isinstance(code, unicode):
def fmt(x): return u"\n".join(strip_common_indent(x.split(u"\n")))
......@@ -189,8 +190,7 @@ class TreeFragment(object):
fmt_pxds = {}
for key, value in pxds.iteritems():
fmt_pxds[key] = fmt(value)
mod = t = parse_from_strings(name, fmt_code, fmt_pxds, level=level)
mod = t = parse_from_strings(name, fmt_code, fmt_pxds, level=level, initial_pos=initial_pos)
if level is None:
t = t.body # Make sure a StatListNode is at the top
if not isinstance(t, StatListNode):
......
......@@ -60,7 +60,7 @@ class Scanner:
queue = None # list of tokens to be returned
trace = 0
def __init__(self, lexicon, stream, name = ''):
def __init__(self, lexicon, stream, name = '', initial_pos = None):
"""
Scanner(lexicon, stream, name = '')
......@@ -84,6 +84,8 @@ class Scanner:
self.cur_line_start = 0
self.cur_char = BOL
self.input_state = 1
if initial_pos is not None:
self.cur_line, self.cur_line_start = initial_pos[1], -initial_pos[2]
def read(self):
"""
......
compiled = False
def empty_decorator(x):
return x
def locals(**arg_types):
return empty_decorator
def cast(type, arg):
# can/should we emulate anything here?
return arg
def sizeof(arg):
# can/should we emulate anything here?
return 1
py_int = int
py_long = long
py_float = float
# They just have to exist...
int = long = char = bint = uint = ulong = longlong = ulonglong = Py_ssize_t = float = double = None
# Void cython.* directives (for case insensitive operating systems).
from Shadow import *
......@@ -2,5 +2,11 @@
# Cython -- Main Program, generic
#
from Cython.Compiler.Main import main
main(command_line = 1)
if __name__ == '__main__':
from Cython.Compiler.Main import main
main(command_line = 1)
else:
# Void cython.* directives.
from Cython.Shadow import *
......@@ -100,7 +100,9 @@ setup(
],
# pyximport
py_modules = ["pyximport/pyximport", "pyximport/pyxbuild"],
py_modules = ["pyximport/__init__",
"pyximport/pyximport",
"pyximport/pyxbuild"],
**setup_args
)
cdef struct point:
double x
double y
double z
cdef foo(int, int i,
list, list L,
point, point p, point* ps)
print sizeof(point*)
cdef foo(int i0, int i, list L0, list L, point p0, point p, point* ps):
pass
cdef class A:
cdef list
cdef list L
# Possibly empty declarators
cdef point(self, int, int i, list, list L, point, point p, point* ps):
pass
cdef class B(A):
cdef point(self, o, int i, oo, list L, ooo, point p, point* ps):
pass
cdef point P
cdef point *Ps
cdef A a
foo(2, 3, [], [], P, P, &P)
a.point("something", 3, "anything", [], "an object", P, &P)
......@@ -10,7 +10,7 @@ cdef class Grail:
pass
_ERRORS = u"""
1:9: Non-default argument follows default argument
1:10: Non-default argument follows default argument
9:16: This argument cannot have a default value
4:23: Non-default argument following default argument
"""
......@@ -4,7 +4,5 @@ def f():
cdef object[e_bufaccess_pxd.T] buf
_ERRORS = u"""
3:17: Syntax error in ctypedef statement
4:31: 'T' is not a type identifier
4:31: 'T' is not declared
3:9: 'nothing' is not a type identifier
"""
def f():
cdef float flt1, flt2, flt3
flt1 = flt2 % flt3 # error
_ERRORS = u"""
/Local/Projects/D/Pyrex/Source/Tests/Errors2/e_modop.pyx:3:13: Invalid operand types for '%' (float; float)
"""
def f():
a = <foao>x
a = <foao>True
_ERRORS = """
2:13: Unknown type
2:9: 'foao' is not a type identifier
"""
\ No newline at end of file
......@@ -48,7 +48,7 @@ __doc__ = ur"""
'with_doc_2(a, b, c)\n\n Existing string\n '
>>> types.__doc__
'types(Ext a, int b, unsigned short int c, float d, e)'
'types(Ext a, int b, unsigned short c, float d, e)'
>>> print (f_c.__doc__)
f_c(char c) -> char
......@@ -61,13 +61,13 @@ __doc__ = ur"""
>>> print (f_s.__doc__)
f_s(short int s) -> short int
f_s(short s) -> short
>>> print (f_us.__doc__)
f_us(unsigned short int s) -> unsigned short int
f_us(unsigned short s) -> unsigned short
>>> print (f_ss.__doc__)
f_ss(signed short int s) -> signed short int
f_ss(signed short s) -> signed short
>>> print (f_i.__doc__)
......@@ -81,23 +81,23 @@ __doc__ = ur"""
>>> print (f_l.__doc__)
f_l(long int l) -> long int
f_l(long l) -> long
>>> print (f_ul.__doc__)
f_ul(unsigned long int l) -> unsigned long int
f_ul(unsigned long l) -> unsigned long
>>> print (f_sl.__doc__)
f_sl(signed long int l) -> signed long int
f_sl(signed long l) -> signed long
>>> print (f_L.__doc__)
f_L(long long int L) -> long long int
f_L(long long L) -> long long
>>> print (f_uL.__doc__)
f_uL(unsigned long long int L) -> unsigned long long int
f_uL(unsigned long long L) -> unsigned long long
>>> print (f_sL.__doc__)
f_sL(signed long long int L) -> signed long long int
f_sL(signed long long L) -> signed long long
>>> print (f_f.__doc__)
......
__doc__ = """
>>> fmod(7, 1.25)
0.75
"""
def fmod(double a, double b):
return a % b
__doc__ = u"""
>>> test_all()
True
"""
cdef class A:
pass
def test_all():
# Optimized tests.
assert isinstance(type('a',(),{}), type)
assert isinstance(bool(), bool)
assert isinstance(int(), int)
assert isinstance(long(), long)
assert isinstance(float(), float)
assert isinstance(complex(), complex)
assert isinstance(bytes(), bytes)
assert isinstance(str(), str)
assert isinstance(unicode(), unicode)
assert isinstance(tuple(), tuple)
assert isinstance(list(), list)
assert isinstance(dict(), dict)
# if py_ver > (2, 3):
# assert isinstance(set(), set)
assert isinstance(slice(0), slice)
assert isinstance(A, type)
assert isinstance(A(), A)
assert not isinstance("foo", int)
# Non-optimized
foo = A
assert isinstance(A(), foo)
assert isinstance(0, (int, long))
assert not isinstance("xyz", (int, long))
return True
__doc__ = """
sage: get_locals(1,2,3)
{'args': (2, 3), 'kwds': {}, 'x': 1, 'y': 'hi', 'z': 5}
"""
def get_locals(x, *args, **kwds):
y = "hi"
cdef int z = 5
return locals()
......@@ -11,4 +11,9 @@ def f():
i = sizeof(p)
i = sizeof(j + k)
i = sizeof(int)
i = sizeof(long int)
i = sizeof(void*)
i = sizeof(Spam)
i = sizeof(Spam*)
i = sizeof(Spam[5])
i = sizeof(Spam (*)())
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