Commit 3b447f81 authored by Stefan Behnel's avatar Stefan Behnel

enable __future__ imports

parent ff7634cb
import __future__
unicode_literals = __future__.unicode_literals
del __future__
...@@ -7,6 +7,12 @@ if sys.version_info[:2] < (2, 2): ...@@ -7,6 +7,12 @@ if sys.version_info[:2] < (2, 2):
sys.stderr.write("Sorry, Cython requires Python 2.2 or later\n") sys.stderr.write("Sorry, Cython requires Python 2.2 or later\n")
sys.exit(1) sys.exit(1)
try:
set
except NameError:
# Python 2.3
from sets import Set as set
from time import time from time import time
import Version import Version
from Scanning import PyrexScanner from Scanning import PyrexScanner
...@@ -30,12 +36,14 @@ class Context: ...@@ -30,12 +36,14 @@ class Context:
# #
# modules {string : ModuleScope} # modules {string : ModuleScope}
# include_directories [string] # include_directories [string]
# future_directives [object]
def __init__(self, include_directories): def __init__(self, include_directories):
#self.modules = {"__builtin__" : BuiltinScope()} #self.modules = {"__builtin__" : BuiltinScope()}
import Builtin import Builtin
self.modules = {"__builtin__" : Builtin.builtin_scope} self.modules = {"__builtin__" : Builtin.builtin_scope}
self.include_directories = include_directories self.include_directories = include_directories
self.future_directives = set()
def find_module(self, module_name, def find_module(self, module_name,
relative_to = None, pos = None, need_pxd = 1): relative_to = None, pos = None, need_pxd = 1):
......
...@@ -11,6 +11,7 @@ import ExprNodes ...@@ -11,6 +11,7 @@ import ExprNodes
from ModuleNode import ModuleNode from ModuleNode import ModuleNode
from Errors import error, InternalError from Errors import error, InternalError
from Cython import Utils from Cython import Utils
import Future
def p_ident(s, message = "Expected an identifier"): def p_ident(s, message = "Expected an identifier"):
if s.sy == 'IDENT': if s.sy == 'IDENT':
...@@ -543,6 +544,12 @@ def p_string_literal(s): ...@@ -543,6 +544,12 @@ def p_string_literal(s):
kind = s.systring[:1].lower() kind = s.systring[:1].lower()
if kind not in "cru": if kind not in "cru":
kind = '' kind = ''
if Future.unicode_literals in s.context.future_directives:
if kind == '':
kind = 'u'
elif kind == 'u':
s.error("string literal must not start with 'u' when importing __future__.unicode_literals")
return ('u', '')
chars = [] chars = []
while 1: while 1:
s.next() s.next()
...@@ -921,7 +928,7 @@ def p_import_statement(s): ...@@ -921,7 +928,7 @@ def p_import_statement(s):
stats.append(stat) stats.append(stat)
return Nodes.StatListNode(pos, stats = stats) return Nodes.StatListNode(pos, stats = stats)
def p_from_import_statement(s): def p_from_import_statement(s, first_statement = 0):
# s.sy == 'from' # s.sy == 'from'
pos = s.position() pos = s.position()
s.next() s.next()
...@@ -938,7 +945,19 @@ def p_from_import_statement(s): ...@@ -938,7 +945,19 @@ def p_from_import_statement(s):
while s.sy == ',': while s.sy == ',':
s.next() s.next()
imported_names.append(p_imported_name(s)) imported_names.append(p_imported_name(s))
if kind == 'cimport': if dotted_name == '__future__':
if not first_statement:
s.error("from __future__ imports must occur at the beginning of the file")
else:
for (name_pos, name, as_name) in imported_names:
try:
directive = getattr(Future, name)
except AttributeError:
s.error("future feature %s is not defined" % name)
break
s.context.future_directives.add(directive)
return Nodes.PassStatNode(pos)
elif kind == 'cimport':
for (name_pos, name, as_name) in imported_names: for (name_pos, name, as_name) in imported_names:
local_name = as_name or name local_name = as_name or name
s.add_type_name(local_name) s.add_type_name(local_name)
...@@ -1200,7 +1219,7 @@ def p_with_statement(s): ...@@ -1200,7 +1219,7 @@ def p_with_statement(s):
s.error("Only 'with gil' and 'with nogil' implemented", s.error("Only 'with gil' and 'with nogil' implemented",
pos = pos) pos = pos)
def p_simple_statement(s): def p_simple_statement(s, first_statement = 0):
#print "p_simple_statement:", s.sy, s.systring ### #print "p_simple_statement:", s.sy, s.systring ###
if s.sy == 'global': if s.sy == 'global':
node = p_global_statement(s) node = p_global_statement(s)
...@@ -1219,7 +1238,7 @@ def p_simple_statement(s): ...@@ -1219,7 +1238,7 @@ def p_simple_statement(s):
elif s.sy in ('import', 'cimport'): elif s.sy in ('import', 'cimport'):
node = p_import_statement(s) node = p_import_statement(s)
elif s.sy == 'from': elif s.sy == 'from':
node = p_from_import_statement(s) node = p_from_import_statement(s, first_statement = first_statement)
elif s.sy == 'assert': elif s.sy == 'assert':
node = p_assert_statement(s) node = p_assert_statement(s)
elif s.sy == 'pass': elif s.sy == 'pass':
...@@ -1228,10 +1247,10 @@ def p_simple_statement(s): ...@@ -1228,10 +1247,10 @@ def p_simple_statement(s):
node = p_expression_or_assignment(s) node = p_expression_or_assignment(s)
return node return node
def p_simple_statement_list(s): def p_simple_statement_list(s, first_statement = 0):
# Parse a series of simple statements on one line # Parse a series of simple statements on one line
# separated by semicolons. # separated by semicolons.
stat = p_simple_statement(s) stat = p_simple_statement(s, first_statement = first_statement)
if s.sy == ';': if s.sy == ';':
stats = [stat] stats = [stat]
while s.sy == ';': while s.sy == ';':
...@@ -1291,7 +1310,8 @@ def p_IF_statement(s, level, cdef_flag, visibility, api): ...@@ -1291,7 +1310,8 @@ def p_IF_statement(s, level, cdef_flag, visibility, api):
s.compile_time_eval = saved_eval s.compile_time_eval = saved_eval
return result return result
def p_statement(s, level, cdef_flag = 0, visibility = 'private', api = 0): def p_statement(s, level, cdef_flag = 0, visibility = 'private', api = 0,
first_statement = 0):
if s.sy == 'ctypedef': if s.sy == 'ctypedef':
if level not in ('module', 'module_pxd'): if level not in ('module', 'module_pxd'):
s.error("ctypedef statement not allowed here") s.error("ctypedef statement not allowed here")
...@@ -1354,16 +1374,18 @@ def p_statement(s, level, cdef_flag = 0, visibility = 'private', api = 0): ...@@ -1354,16 +1374,18 @@ def p_statement(s, level, cdef_flag = 0, visibility = 'private', api = 0):
elif s.sy == 'with': elif s.sy == 'with':
return p_with_statement(s) return p_with_statement(s)
else: else:
return p_simple_statement_list(s) return p_simple_statement_list(s, first_statement = first_statement)
def p_statement_list(s, level, def p_statement_list(s, level,
cdef_flag = 0, visibility = 'private', api = 0): cdef_flag = 0, visibility = 'private', api = 0, first_statement = 0):
# Parse a series of statements separated by newlines. # Parse a series of statements separated by newlines.
pos = s.position() pos = s.position()
stats = [] stats = []
while s.sy not in ('DEDENT', 'EOF'): while s.sy not in ('DEDENT', 'EOF'):
stats.append(p_statement(s, level, stats.append(p_statement(s, level,
cdef_flag = cdef_flag, visibility = visibility, api = api)) cdef_flag = cdef_flag, visibility = visibility, api = api,
first_statement = first_statement))
first_statement = 0
if len(stats) == 1: if len(stats) == 1:
return stats[0] return stats[0]
else: else:
...@@ -2118,7 +2140,7 @@ def p_module(s, pxd, full_module_name): ...@@ -2118,7 +2140,7 @@ def p_module(s, pxd, full_module_name):
level = 'module_pxd' level = 'module_pxd'
else: else:
level = 'module' level = 'module'
body = p_statement_list(s, level) body = p_statement_list(s, level, first_statement = 1)
if s.sy != 'EOF': if s.sy != 'EOF':
s.error("Syntax error in statement [%s,%s]" % ( s.error("Syntax error in statement [%s,%s]" % (
repr(s.sy), repr(s.systring))) repr(s.sy), repr(s.systring)))
......
from __future__ import unicode_literals
import sys
if sys.version_info[0] >= 3:
__doc__ = """
>>> u == 'test'
True
>>> isinstance(u, str)
True
"""
else:
__doc__ = """
>>> u == u'test'
True
>>> isinstance(u, unicode)
True
"""
u = "test"
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