from Cython.Utils import open_new_file, open_source_file
from PyrexTypes import py_object_type, typecast
from TypeSlots import method_coexist
+from Scanning import SourceDescriptor
class CCodeWriter:
# f file output file
def get_py_version_hex(self, pyversion):
return "0x%02X%02X%02X%02X" % (tuple(pyversion) + (0,0,0,0))[:4]
- def file_contents(self, file):
+ def file_contents(self, source_desc):
try:
- return self.input_file_contents[file]
+ return self.input_file_contents[source_desc]
except KeyError:
F = [line.encode('ASCII', 'replace').replace(
'*/', '*[inserted by cython to avoid comment closer]/')
- for line in open_source_file(file)]
- self.input_file_contents[file] = F
+ for line in source_desc.get_lines(decode=True)]
+ self.input_file_contents[source_desc] = F
return F
def mark_pos(self, pos):
if pos is None:
return
- filename, line, col = pos
- contents = self.file_contents(filename)
+ source_desc, line, col = pos
+ assert isinstance(source_desc, SourceDescriptor)
+ contents = self.file_contents(source_desc)
context = ''
for i in range(max(0,line-3), min(line+2, len(contents))):
s = s.rstrip() + ' # <<<<<<<<<<<<<< ' + '\n'
context += " * " + s
- marker = '"%s":%d\n%s' % (filename.encode('ASCII', 'replace'), line, context)
+ marker = '"%s":%d\n%s' % (str(source_desc).encode('ASCII', 'replace'), line, context)
if self.last_marker != marker:
self.marker = marker
class PyrexWarning(Exception):
pass
+
def context(position):
- F = open(position[0]).readlines()
- s = ''.join(F[position[1]-6:position[1]])
+ source = position[0]
+ assert not (isinstance(source, unicode) or isinstance(source, str)), (
+ "Please replace filename strings with Scanning.FileSourceDescriptor instances %r" % source)
+ F = list(source.get_lines())
+ s = ''.join(F[min(0, position[1]-6):position[1]])
s += ' '*(position[2]-1) + '^'
s = '-'*60 + '\n...\n' + s + '\n' + '-'*60 + '\n'
return s
-
+
class CompileError(PyrexError):
def __init__(self, position = None, message = ""):
from time import time
import Version
-from Scanning import PyrexScanner
+from Scanning import PyrexScanner, FileSourceDescriptor
import Errors
from Errors import PyrexError, CompileError, error
import Parsing
try:
if debug_find_module:
print("Context.find_module: Parsing %s" % pxd_pathname)
- pxd_tree = self.parse(pxd_pathname, scope.type_names, pxd = 1,
+ source_desc = FileSourceDescriptor(pxd_pathname)
+ pxd_tree = self.parse(source_desc, scope.type_names, pxd = 1,
full_module_name = module_name)
pxd_tree.analyse_declarations(scope)
except CompileError:
# 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
for dir in dirs:
path = os.path.join(dir, filename)
self.modules[name] = scope
return scope
- def parse(self, source_filename, type_names, pxd, full_module_name):
- name = Utils.encode_filename(source_filename)
+ def parse(self, source_desc, type_names, pxd, full_module_name):
+ if not isinstance(source_desc, FileSourceDescriptor):
+ raise RuntimeError("Only file sources for code supported")
+ source_filename = Utils.encode_filename(source_desc.filename)
# Parse the given source file and return a parse tree.
try:
f = Utils.open_source_file(source_filename, "rU")
try:
- s = PyrexScanner(f, name, source_encoding = f.encoding,
+ s = PyrexScanner(f, source_desc, source_encoding = f.encoding,
type_names = type_names, context = self)
tree = Parsing.p_module(s, pxd, full_module_name)
finally:
f.close()
except UnicodeDecodeError, msg:
- error((name, 0, 0), "Decoding error, missing or incorrect coding=<encoding-name> at top of source (%s)" % msg)
+ error((source_desc, 0, 0), "Decoding error, missing or incorrect coding=<encoding-name> at top of source (%s)" % msg)
if Errors.num_errors > 0:
raise CompileError
return tree
except EnvironmentError:
pass
module_name = full_module_name # 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
if any_failures:
sys.exit(1)
+
+
#------------------------------------------------------------------------
#
# Set the default options depending on the platform
code.putln("")
code.putln("static char *%s[] = {" % Naming.filenames_cname)
if code.filename_list:
- for filename in code.filename_list:
- filename = os.path.basename(filename)
+ for source_desc in code.filename_list:
+ filename = os.path.basename(str(source_desc))
escaped_filename = filename.replace("\\", "\\\\").replace('"', r'\"')
code.putln('"%s",' %
escaped_filename)
import os, re
from string import join, replace
from types import ListType, TupleType
-from Scanning import PyrexScanner
+from Scanning import PyrexScanner, FileSourceDescriptor
import Nodes
import ExprNodes
from ModuleNode import ModuleNode
include_file_path = s.context.find_include_file(include_file_name, pos)
if include_file_path:
f = Utils.open_source_file(include_file_path, mode="rU")
- s2 = PyrexScanner(f, include_file_path, s, source_encoding=f.encoding)
+ source_desc = FileSourceDescriptor(include_file_path)
+ s2 = PyrexScanner(f, source_desc, s, source_encoding=f.encoding)
try:
tree = p_statement_list(s2, level)
finally:
from Errors import CompileError, error
from Lexicon import string_prefixes, make_lexicon
+from Cython import Utils
+
plex_version = getattr(Plex, '_version', None)
#print "Plex version:", plex_version ###
#------------------------------------------------------------------
+class SourceDescriptor:
+ pass
+
+class FileSourceDescriptor(SourceDescriptor):
+ """
+ Represents a code source. A code source is a more generic abstraction
+ for a "filename" (as sometimes the code doesn't come from a file).
+ Instances of code sources are passed to Scanner.__init__ as the
+ optional name argument and will be passed back when asking for
+ the position()-tuple.
+ """
+ def __init__(self, filename):
+ self.filename = filename
+
+ def get_lines(self, decode=False):
+ # decode is True when called from Code.py (which reserializes in a standard way to ASCII),
+ # while decode is False when called from Errors.py.
+ #
+ # Note that if changing Errors.py in this respect, raising errors over wrong encoding
+ # will no longer be able to produce the line where the encoding problem occurs ...
+ if decode:
+ return Utils.open_source_file(self.filename)
+ else:
+ return open(self.filename)
+
+ def __str__(self):
+ return self.filename
+
+ def __repr__(self):
+ return "<FileSourceDescriptor:%s>" % self
+
+class StringSourceDescriptor(SourceDescriptor):
+ """
+ Instances of this class can be used instead of a filenames if the
+ code originates from a string object.
+ """
+ def __init__(self, name, code):
+ self.name = name
+ self.codelines = [x + "\n" for x in code.split("\n")]
+
+ def get_lines(self, decode=False):
+ return self.codelines
+
+ def __str__(self):
+ return self.name
+
+ def __repr__(self):
+ return "<StringSourceDescriptor:%s>" % self
+
+#------------------------------------------------------------------
+
class PyrexScanner(Scanner):
# context Context Compilation context
# type_names set Identifiers to be treated as type names