From 4f3af12a5b8ee3a8109dd6f8c8ff01bcfe3cae33 Mon Sep 17 00:00:00 2001 From: Stefan Behnel Date: Sat, 16 Apr 2011 12:05:10 +0200 Subject: [PATCH] clean up special casing of non-portable builtin types, add option for disabling errors on unknown names --- Cython/Compiler/Code.py | 31 +++++++++++++++---------------- Cython/Compiler/ModuleNode.py | 22 ++++++++++++---------- Cython/Compiler/Options.py | 11 ++++++++++- Cython/Compiler/Symtab.py | 16 ++++++++++++---- 4 files changed, 49 insertions(+), 31 deletions(-) diff --git a/Cython/Compiler/Code.py b/Cython/Compiler/Code.py index c70318a2..c23e11fa 100644 --- a/Cython/Compiler/Code.py +++ b/Cython/Compiler/Code.py @@ -23,6 +23,14 @@ try: except ImportError: from builtins import str as basestring + +non_portable_builtins_map = { + 'bytes' : ('PY_MAJOR_VERSION < 3', 'str'), + 'unicode' : ('PY_MAJOR_VERSION >= 3', 'str'), + 'xrange' : ('PY_MAJOR_VERSION >= 3', 'range'), + 'BaseException' : ('PY_VERSION_HEX < 0x02050000', 'Exception'), + } + class UtilityCode(object): # Stores utility code to add during code generation. # @@ -651,31 +659,22 @@ class GlobalState(object): return "%s%s%d" % (Naming.const_prefix, prefix, n) def add_cached_builtin_decl(self, entry): - if Options.cache_builtins: + if entry.is_builtin and entry.is_const: if self.should_declare(entry.cname, entry): self.put_pyobject_decl(entry) w = self.parts['cached_builtins'] - conditional_name = False - if entry.name == 'xrange': - # replaced by range() in Py3 - conditional_name = True - w.putln('#if PY_MAJOR_VERSION >= 3') - self.put_cached_builtin_init( - entry.pos, StringEncoding.EncodedString('range'), - entry.cname) - elif entry.name == 'BaseException': - # replace BaseException by Exception in Py<2.5 - conditional_name = True - w.putln('#if PY_VERSION_HEX < 0x02050000') + condition = None + if entry.name in non_portable_builtins_map: + condition, replacement = non_portable_builtins_map[entry.name] + w.putln('#if %s' % condition) self.put_cached_builtin_init( - entry.pos, StringEncoding.EncodedString('Exception'), + entry.pos, StringEncoding.EncodedString(replacement), entry.cname) - if conditional_name: w.putln('#else') self.put_cached_builtin_init( entry.pos, StringEncoding.EncodedString(entry.name), entry.cname) - if conditional_name: + if condition: w.putln('#endif') def put_cached_builtin_init(self, pos, name, cname): diff --git a/Cython/Compiler/ModuleNode.py b/Cython/Compiler/ModuleNode.py index 459a89d7..7ce1c841 100644 --- a/Cython/Compiler/ModuleNode.py +++ b/Cython/Compiler/ModuleNode.py @@ -2134,19 +2134,21 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): else: objstruct = "struct %s" % type.objstruct_cname module_name = type.module_name + condition = None if module_name not in ('__builtin__', 'builtins'): module_name = '"%s"' % module_name else: module_name = '__Pyx_BUILTIN_MODULE_NAME' - if type.name in self.py3_type_name_map: - code.putln("#if PY_MAJOR_VERSION >= 3") - code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), 1); %s' % ( - type.typeptr_cname, - module_name, - self.py3_type_name_map[type.name], - objstruct, - error_code)) - code.putln("#else") + if type.name in Code.non_portable_builtins_map: + condition, replacement = Code.non_portable_builtins_map[entry.name] + code.putln("#if %s" % condition) + code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), 1); %s' % ( + type.typeptr_cname, + module_name, + replacement, + objstruct, + error_code)) + code.putln("#else") code.putln('%s = __Pyx_ImportType(%s, "%s", sizeof(%s), %i); %s' % ( type.typeptr_cname, module_name, @@ -2154,7 +2156,7 @@ class ModuleNode(Nodes.Node, Nodes.BlockNode): objstruct, not type.is_external or type.is_subclassed, error_code)) - if type.name in self.py3_type_name_map: + if condition: code.putln("#endif") def generate_type_ready_code(self, env, entry, code): diff --git a/Cython/Compiler/Options.py b/Cython/Compiler/Options.py index 2e3663ae..a38cc373 100644 --- a/Cython/Compiler/Options.py +++ b/Cython/Compiler/Options.py @@ -2,7 +2,10 @@ # Cython - Compilation-wide options and pragma declarations # -cache_builtins = True # Perform lookups on builtin names only once +# Perform lookups on builtin names only once, at module initialisation +# time. This will prevent the module from getting imported if a +# builtin name that it uses cannot be found during initialisation. +cache_builtins = True embed_pos_in_docstring = False gcc_branch_hints = True @@ -25,6 +28,12 @@ fast_fail = False # Make all warnings into errors. warning_errors = False +# Make unknown names an error. Python raises a NameError when +# encountering unknown names at runtime, whereas this option makes +# them a compile time error. If you want full Python compatibility, +# you should disable this option and also 'cache_builtins'. +error_on_unknown_names = True + # This will convert statements of the form "for i in range(...)" # to "for i from ..." when i is a cdef'd integer type, and the direction # (i.e. sign of step) can be determined. diff --git a/Cython/Compiler/Symtab.py b/Cython/Compiler/Symtab.py index d52317bb..6d6f7e1c 100644 --- a/Cython/Compiler/Symtab.py +++ b/Cython/Compiler/Symtab.py @@ -760,7 +760,10 @@ class BuiltinScope(Scope): if self.outer_scope is not None: return self.outer_scope.declare_builtin(name, pos) else: - warning(pos, "undeclared name not builtin: %s" % name, 2) + if Options.error_on_unknown_names: + error(pos, "undeclared name not builtin: %s" % name) + else: + warning(pos, "undeclared name not builtin: %s" % name, 2) def declare_builtin_cfunction(self, name, type, cname, python_equiv = None, utility_code = None): @@ -802,6 +805,8 @@ class BuiltinScope(Scope): var_entry.is_readonly = 1 var_entry.is_builtin = 1 var_entry.utility_code = utility_code + if Options.cache_builtins: + var_entry.is_const = True entry.as_variable = var_entry return type @@ -911,7 +916,7 @@ class ModuleScope(Scope): return self.outer_scope.lookup(name, language_level = self.context.language_level) def declare_builtin(self, name, pos): - if not hasattr(builtins, name) and name not in ('xrange', 'BaseException'): + if not hasattr(builtins, name) and name not in Code.non_portable_builtins_map: # 'xrange' and 'BaseException' are special cased in Code.py if self.has_import_star: entry = self.declare_var(name, py_object_type, pos) @@ -922,7 +927,10 @@ class ModuleScope(Scope): ## return entry else: # unknown - assume it's builtin and look it up at runtime - warning(pos, "undeclared name not builtin: %s" % name, 2) + if Options.error_on_unknown_names: + error(pos, "undeclared name not builtin: %s" % name) + else: + warning(pos, "undeclared name not builtin: %s" % name, 2) entry = self.declare(name, None, py_object_type, pos, 'private') entry.is_builtin = 1 return entry @@ -933,7 +941,7 @@ class ModuleScope(Scope): entry = self.declare(None, None, py_object_type, pos, 'private') if Options.cache_builtins: entry.is_builtin = 1 - entry.is_const = 1 + entry.is_const = 1 # cached entry.name = name entry.cname = Naming.builtin_prefix + name self.cached_builtins.append(entry) -- 2.26.2