from sets import Set as set
from time import time
+ import Code
+ import Errors
+ import Parsing
import Version
- import Errors
+from Scanning import PyrexScanner, FileSourceDescriptor
from Errors import PyrexError, CompileError, error
- import Parsing
-from Scanning import PyrexScanner
from Symtab import BuiltinScope, ModuleScope
- import Code
- from Cython.Utils import replace_suffix
from Cython import Utils
-import Transform
+
+# Note: PHASES and TransformSet should be removed soon; but that's for
+# another day and another commit.
+PHASES = [
+ 'before_analyse_function', # run in FuncDefNode.generate_function_definitions
+ 'after_analyse_function' # run in FuncDefNode.generate_function_definitions
+]
+
+class TransformSet(dict):
+ def __init__(self):
+ for name in PHASES:
+ self[name] = []
+ def run(self, name, node, **options):
+ assert name in self, "Transform phase %s not defined" % name
+ for transform in self[name]:
+ transform(node, phase=name, **options)
verbose = 0
# None if not found, but does not report an error.
dirs = self.include_directories
if pos:
- here_dir = os.path.dirname(pos[0])
+ file_desc = pos[0]
+ if not isinstance(file_desc, FileSourceDescriptor):
+ raise RuntimeError("Only file sources for code supported")
+ here_dir = os.path.dirname(file_desc.filename)
dirs = [here_dir] + dirs
+
+ dotted_filename = qualified_name + suffix
+ if split_package:
+ names = qualified_name.split('.')
+ package_names = names[:-1]
+ module_name = names[-1]
+ module_filename = module_name + suffix
+ package_filename = "__init__" + suffix
+
for dir in dirs:
- path = os.path.join(dir, filename)
+ path = os.path.join(dir, dotted_filename)
if os.path.exists(path):
return path
+ if split_package:
+ package_dir = self.check_package_dir(dir, package_names)
+ if package_dir is not None:
+ path = os.path.join(package_dir, module_filename)
+ if os.path.exists(path):
+ return path
+ path = os.path.join(dir, package_dir, module_name,
+ package_filename)
+ if os.path.exists(path):
+ return path
return None
+ def check_package_dir(self, dir, package_names):
+ package_dir = os.path.join(dir, *package_names)
+ if not os.path.exists(package_dir):
+ return None
+ for dirname in package_names:
+ dir = os.path.join(dir, dirname)
+ package_init = os.path.join(dir, "__init__.py")
+ if not os.path.exists(package_init) and \
+ not os.path.exists(package_init + "x"): # same with .pyx ?
+ return None
+ return package_dir
+
+ def c_file_out_of_date(self, source_path):
+ c_path = Utils.replace_suffix(source_path, ".c")
+ if not os.path.exists(c_path):
+ return 1
+ c_time = Utils.modification_time(c_path)
+ if Utils.file_newer_than(source_path, c_time):
+ return 1
+ pos = [source_path]
+ pxd_path = Utils.replace_suffix(source_path, ".pxd")
+ if os.path.exists(pxd_path) and Utils.file_newer_than(pxd_path, c_time):
+ return 1
+ for kind, name in self.read_dependency_file(source_path):
+ if kind == "cimport":
+ dep_path = self.find_pxd_file(name, pos)
+ elif kind == "include":
+ dep_path = self.search_include_directories(name, pos)
+ else:
+ continue
+ if dep_path and Utils.file_newer_than(dep_path, c_time):
+ return 1
+ return 0
+
+ def find_cimported_module_names(self, source_path):
+ return [ name for kind, name in self.read_dependency_file(source_path)
+ if kind == "cimport" ]
+
+ def is_package_dir(self, dir_path):
+ # Return true if the given directory is a package directory.
+ for filename in ("__init__.py", "__init__.pyx"):
+ path = os.path.join(dir_path, filename)
+ if os.path.exists(path):
+ return 1
+
+ def read_dependency_file(self, source_path):
+ dep_path = replace_suffix(source_path, ".dep")
+ if os.path.exists(dep_path):
+ f = open(dep_path, "rU")
+ chunks = [ line.strip().split(" ", 1)
+ for line in f.readlines()
+ if " " in line.strip() ]
+ f.close()
+ return chunks
+ else:
+ return ()
+
def lookup_submodule(self, name):
# Look up a top-level module. Returns None if not found.
return self.modules.get(name, None)
c_suffix = ".cpp"
else:
c_suffix = ".c"
- result.c_file = replace_suffix(source, c_suffix)
- result.c_file = Utils.replace_suffix(source, c_suffix)
++ result.c_file = Utils .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 = full_module_name # self.extract_module_name(source, options)
+ module_name = full_module_name or self.extract_module_name(source, options)
+ source = FileSourceDescriptor(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, full_module_name = full_module_name)
- tree = self.parse(source, scope, pxd = 0,
++ tree = self.parse(source, scope.type_names, pxd = 0,
+ full_module_name = full_module_name)
tree.process_implementation(scope, options, result)
except CompileError:
errors_occurred = True
output_file = None,
annotate = False,
generate_pxi = 0,
- working_path = "")
-
+ transforms = TransformSet(),
- quiet = 0,
- transforms = Transform.TransformSet(),
- working_path = "")
-
++ working_path = "",
+ recursive = 0,
+ timestamps = None,
+ verbose = 0,
++ quiet = 0)
if sys.platform == "mac":
from Cython.Mac.MacSystem import c_compile, c_link, CCompilerError
default_options['use_listing_file'] = 1
def __init__(self, pos, **kw):
self.pos = pos
self.__dict__.update(kw)
-
+
+ gil_message = "Operation"
+
+ def gil_check(self, env):
+ if env.nogil:
+ self.gil_error()
+
+ def gil_error(self):
+ error(self.pos, "%s not allowed without gil" % self.gil_message)
+
- def get_child_accessors(self):
- """Returns an iterator over the children of the Node. Each member in the
- iterated list is an object with get(), set(value), and name() methods,
- which can be used to fetch and replace the child and query the name
- the relation this node has with the child. For instance, for an
- assignment node, this code:
-
- for child in assignment_node.get_child_accessors():
- print(child.name())
- child.set(i_node)
-
- will print "lhs", "rhs", and change the assignment statement to "i = i"
- (assuming that i_node is a node able to represent the variable i in the
- tree).
-
- Any kind of objects can in principle be returned, but the typical
- candidates are either Node instances or lists of node instances.
-
- The object returned in each iteration stage can only be used until the
- iterator is advanced to the next child attribute. (However, the objects
- returned by the get() function can be kept).
-
- Typically, a Node instance will have other interesting and potentially
- hierarchical attributes as well. These must be explicitly accessed -- this
- method only provides access to attributes that are deemed to naturally
- belong in the parse tree.
-
- Descandant classes can either specify child_attrs, override get_child_attrs,
- or override this method directly in order to provide access to their
- children. All descendants of Node *must* declare their children -- leaf nodes
- should simply declare "child_attrs = []".
- """
- attrnames = self.get_child_attrs()
- if attrnames is None:
- raise InternalError("Children access not implemented for %s" % \
- self.__class__.__name__)
- return _AttributeIterator(self, attrnames)
-
- def get_child_attrs(self):
- """Utility method for more easily implementing get_child_accessors.
- If you override get_child_accessors then this method is not used."""
- return self.child_attrs
+ def clone_node(self):
+ """Clone the node. This is defined as a shallow copy, except for member lists
+ amongst the child attributes (from get_child_accessors) which are also
+ copied. Lists containing child nodes are thus seen as a way for the node
+ to hold multiple children directly; the list is not treated as a seperate
+ level in the tree."""
+ result = copy.copy(self)
+ for attrname in result.child_attrs:
+ value = getattr(result, attrname)
+ if isinstance(value, list):
+ setattr(result, attrname, value)
+ return result
#