cython-devel
changeset 3484:b254c4dbc089
support for some Python 3 (or 2.6+) syntax features (found by test_grammar.py in Py3.1.1):
- oct/bin notation: 0o12345, 0b10101
- function annotations (only pure syntax support, not currently used)
also: allow decorators on inner functions
- oct/bin notation: 0o12345, 0b10101
- function annotations (only pure syntax support, not currently used)
also: allow decorators on inner functions
| author | Stefan Behnel <scoder@users.berlios.de> |
|---|---|
| date | Thu Jan 28 23:05:39 2010 +0100 (2 years ago) |
| parents | 055afa21b34b |
| children | 3e25233bbcc7 |
| files | Cython/Compiler/ExprNodes.py Cython/Compiler/Lexicon.py Cython/Compiler/Nodes.py Cython/Compiler/Parsing.pxd Cython/Compiler/Parsing.py Cython/Utils.py |
line diff
1.1 --- a/Cython/Compiler/ExprNodes.py Wed Jan 06 11:05:39 2010 -0800
1.2 +++ b/Cython/Compiler/ExprNodes.py Thu Jan 28 23:05:39 2010 +0100
1.3 @@ -19,6 +19,7 @@
1.4 import Symtab
1.5 import Options
1.6 from Annotate import AnnotationItem
1.7 +from Cython import Utils
1.8
1.9 from Cython.Debugging import print_call_chain
1.10 from DebugFlags import debug_disposal_code, debug_temp_alloc, \
1.11 @@ -771,16 +772,23 @@
1.12 self.result_code = self.get_constant_c_result_code()
1.13
1.14 def get_constant_c_result_code(self):
1.15 - return str(self.value) + self.unsigned + self.longness
1.16 + value = self.value
1.17 + if isinstance(value, basestring) and len(value) > 2:
1.18 + # must convert C-incompatible Py3 oct/bin notations
1.19 + if value[1] in 'oO':
1.20 + value = value[0] + value[2:] # '0o123' => '0123'
1.21 + elif value[1] in 'bB':
1.22 + value = int(value[2:], 2)
1.23 + return str(value) + self.unsigned + self.longness
1.24
1.25 def calculate_result_code(self):
1.26 return self.result_code
1.27
1.28 def calculate_constant_result(self):
1.29 - self.constant_result = int(self.value, 0)
1.30 -
1.31 - def compile_time_value(self, denv):
1.32 - return int(self.value, 0)
1.33 + self.constant_result = Utils.str_to_number(self.value)
1.34 +
1.35 + def compile_time_value(self, denv):
1.36 + return Utils.str_to_number(self.value)
1.37
1.38
1.39 class FloatNode(ConstNode):
1.40 @@ -966,10 +974,10 @@
1.41 type = py_object_type
1.42
1.43 def calculate_constant_result(self):
1.44 - self.constant_result = long(self.value)
1.45 -
1.46 - def compile_time_value(self, denv):
1.47 - return long(self.value)
1.48 + self.constant_result = Utils.str_to_number(self.value)
1.49 +
1.50 + def compile_time_value(self, denv):
1.51 + return Utils.str_to_number(self.value)
1.52
1.53 def analyse_types(self, env):
1.54 self.is_temp = 1
2.1 --- a/Cython/Compiler/Lexicon.py Wed Jan 06 11:05:39 2010 -0800
2.2 +++ b/Cython/Compiler/Lexicon.py Thu Jan 28 23:05:39 2010 +0100
2.3 @@ -17,6 +17,7 @@
2.4
2.5 letter = Any("ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz_")
2.6 digit = Any("0123456789")
2.7 + bindigit = Any("01")
2.8 octdigit = Any("01234567")
2.9 hexdigit = Any("0123456789ABCDEFabcdef")
2.10 indentation = Bol + Rep(Any(" \t"))
2.11 @@ -27,7 +28,9 @@
2.12 decimal_fract = (decimal + dot + Opt(decimal)) | (dot + decimal)
2.13
2.14 name = letter + Rep(letter | digit)
2.15 - intconst = decimal | (Str("0x") + Rep1(hexdigit))
2.16 + intconst = decimal | (Str("0") + ((Any("Xx") + Rep1(hexdigit)) |
2.17 + (Any("Oo") + Rep1(octdigit)) |
2.18 + (Any("Bb") + Rep1(bindigit)) ))
2.19 intsuffix = (Opt(Any("Uu")) + Opt(Any("Ll")) + Opt(Any("Ll"))) | (Opt(Any("Ll")) + Opt(Any("Ll")) + Opt(Any("Uu")))
2.20 intliteral = intconst + intsuffix
2.21 fltconst = (decimal_fract + Opt(exponent)) | (decimal + exponent)
2.22 @@ -75,7 +78,7 @@
2.23 punct = Any(":,;+-*/|&<>=.%`~^?")
2.24 diphthong = Str("==", "<>", "!=", "<=", ">=", "<<", ">>", "**", "//",
2.25 "+=", "-=", "*=", "/=", "%=", "|=", "^=", "&=",
2.26 - "<<=", ">>=", "**=", "//=")
2.27 + "<<=", ">>=", "**=", "//=", "->")
2.28 spaces = Rep1(Any(" \t\f"))
2.29 escaped_newline = Str("\\\n")
2.30 lineterm = Eol + Opt(Str("\n"))
3.1 --- a/Cython/Compiler/Nodes.py Wed Jan 06 11:05:39 2010 -0800
3.2 +++ b/Cython/Compiler/Nodes.py Thu Jan 28 23:05:39 2010 +0100
3.3 @@ -597,6 +597,7 @@
3.4 # not_none boolean Tagged with 'not None'
3.5 # default ExprNode or None
3.6 # default_value PyObjectConst constant for default value
3.7 + # annotation ExprNode or None Py3 function arg annotation
3.8 # is_self_arg boolean Is the "self" arg of an extension type method
3.9 # is_kw_only boolean Is a keyword-only argument
3.10
3.11 @@ -607,6 +608,7 @@
3.12 type = None
3.13 name_declarator = None
3.14 default_value = None
3.15 + annotation = None
3.16
3.17 def analyse(self, env, nonempty = 0):
3.18 #print "CArgDeclNode.analyse: is_self_arg =", self.is_self_arg ###
3.19 @@ -1603,8 +1605,9 @@
3.20 # Argument which must be a Python object (used
3.21 # for * and ** arguments).
3.22 #
3.23 - # name string
3.24 - # entry Symtab.Entry
3.25 + # name string
3.26 + # entry Symtab.Entry
3.27 + # annotation ExprNode or None Py3 argument annotation
3.28 child_attrs = []
3.29
3.30
3.31 @@ -1626,6 +1629,8 @@
3.32 # starstar_arg PyArgDeclNode or None ** argument
3.33 # doc EncodedString or None
3.34 # body StatListNode
3.35 + # return_type_annotation
3.36 + # ExprNode or None the Py3 return type annotation
3.37 #
3.38 # The following subnode is constructed internally
3.39 # when the def statement is inside a Python class definition.
3.40 @@ -1641,6 +1646,7 @@
3.41 reqd_kw_flags_cname = "0"
3.42 is_wrapper = 0
3.43 decorators = None
3.44 + return_type_annotation = None
3.45 entry = None
3.46 acquire_gil = 0
3.47
3.48 @@ -1685,7 +1691,7 @@
3.49 cfunc_type = cfunc.type
3.50 if len(self.args) != len(cfunc_type.args) or cfunc_type.has_varargs:
3.51 error(self.pos, "wrong number of arguments")
3.52 - error(declarator.pos, "previous declaration here")
3.53 + error(cfunc.pos, "previous declaration here")
3.54 for formal_arg, type_arg in zip(self.args, cfunc_type.args):
3.55 name_declarator, type = formal_arg.analyse(cfunc.scope, nonempty=1)
3.56 if type is None or type is PyrexTypes.py_object_type or formal_arg.is_self:
4.1 --- a/Cython/Compiler/Parsing.pxd Wed Jan 06 11:05:39 2010 -0800
4.2 +++ b/Cython/Compiler/Parsing.pxd Thu Jan 28 23:05:39 2010 +0100
4.3 @@ -126,9 +126,9 @@
4.4 cpdef p_with_gil(PyrexScanner s)
4.5 cpdef p_exception_value_clause(PyrexScanner s)
4.6 cpdef p_c_arg_list(PyrexScanner s, ctx = *, bint in_pyfunc = *, bint cmethod_flag = *,
4.7 - bint nonempty_declarators = *, bint kw_only = *)
4.8 + bint nonempty_declarators = *, bint kw_only = *, bint annotated = *)
4.9 cpdef p_optional_ellipsis(PyrexScanner s)
4.10 -cpdef p_c_arg_decl(PyrexScanner s, ctx, in_pyfunc, bint cmethod_flag = *, bint nonempty = *, bint kw_only = *)
4.11 +cpdef p_c_arg_decl(PyrexScanner s, ctx, in_pyfunc, bint cmethod_flag = *, bint nonempty = *, bint kw_only = *, bint annotated = *)
4.12 cpdef p_api(PyrexScanner s)
4.13 cpdef p_cdef_statement(PyrexScanner s, ctx)
4.14 cpdef p_cdef_block(PyrexScanner s, ctx)
4.15 @@ -143,7 +143,7 @@
4.16 cpdef p_ctypedef_statement(PyrexScanner s, ctx)
4.17 cpdef p_decorators(PyrexScanner s)
4.18 cpdef p_def_statement(PyrexScanner s, list decorators = *)
4.19 -cpdef p_varargslist(PyrexScanner s, terminator=*)
4.20 +cpdef p_varargslist(PyrexScanner s, terminator=*, bint annotated = *)
4.21 cpdef p_py_arg_decl(PyrexScanner s)
4.22 cpdef p_class_statement(PyrexScanner s, decorators)
4.23 cpdef p_c_class_definition(PyrexScanner s, pos, ctx)
5.1 --- a/Cython/Compiler/Parsing.py Wed Jan 06 11:05:39 2010 -0800
5.2 +++ b/Cython/Compiler/Parsing.py Thu Jan 28 23:05:39 2010 +0100
5.3 @@ -113,7 +113,8 @@
5.4 args = []
5.5 star_arg = starstar_arg = None
5.6 else:
5.7 - args, star_arg, starstar_arg = p_varargslist(s, terminator=':')
5.8 + args, star_arg, starstar_arg = p_varargslist(
5.9 + s, terminator=':', annotated=False)
5.10 s.expect(':')
5.11 if allow_conditional:
5.12 expr = p_simple_expr(s)
5.13 @@ -1215,6 +1216,8 @@
5.14 imported_names = [p_imported_name(s, is_cimport)]
5.15 while s.sy == ',':
5.16 s.next()
5.17 + if is_parenthesized and s.sy == ')':
5.18 + break
5.19 imported_names.append(p_imported_name(s, is_cimport))
5.20 if is_parenthesized:
5.21 s.expect(')')
5.22 @@ -1464,7 +1467,7 @@
5.23 exc_value = None
5.24 if s.sy != ':':
5.25 exc_type = p_simple_expr(s)
5.26 - if s.sy == ',':
5.27 + if s.sy == ',' or (s.sy == 'IDENT' and s.systring == 'as'):
5.28 s.next()
5.29 exc_value = p_simple_expr(s)
5.30 body = p_suite(s)
5.31 @@ -1625,7 +1628,7 @@
5.32 elif s.sy == 'IF':
5.33 return p_IF_statement(s, ctx)
5.34 elif s.sy == 'DECORATOR':
5.35 - if ctx.level not in ('module', 'class', 'c_class', 'property', 'module_pxd', 'c_class_pxd'):
5.36 + if ctx.level not in ('module', 'class', 'c_class', 'function', 'property', 'module_pxd', 'c_class_pxd'):
5.37 print ctx.level
5.38 s.error('decorator not allowed here')
5.39 s.level = ctx.level
5.40 @@ -2143,14 +2146,15 @@
5.41 c_arg_list_terminators = ('*', '**', '.', ')')
5.42
5.43 def p_c_arg_list(s, ctx = Ctx(), in_pyfunc = 0, cmethod_flag = 0,
5.44 - nonempty_declarators = 0, kw_only = 0):
5.45 + nonempty_declarators = 0, kw_only = 0, annotated = 1):
5.46 # Comma-separated list of C argument declarations, possibly empty.
5.47 # May have a trailing comma.
5.48 args = []
5.49 is_self_arg = cmethod_flag
5.50 while s.sy not in c_arg_list_terminators:
5.51 args.append(p_c_arg_decl(s, ctx, in_pyfunc, is_self_arg,
5.52 - nonempty = nonempty_declarators, kw_only = kw_only))
5.53 + nonempty = nonempty_declarators, kw_only = kw_only,
5.54 + annotated = annotated))
5.55 if s.sy != ',':
5.56 break
5.57 s.next()
5.58 @@ -2164,10 +2168,12 @@
5.59 else:
5.60 return 0
5.61
5.62 -def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0, kw_only = 0):
5.63 +def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0,
5.64 + kw_only = 0, annotated = 1):
5.65 pos = s.position()
5.66 not_none = 0
5.67 default = None
5.68 + annotation = None
5.69 base_type = p_c_base_type(s, cmethod_flag, nonempty = nonempty)
5.70 declarator = p_c_declarator(s, ctx, nonempty = nonempty)
5.71 if s.sy == 'not':
5.72 @@ -2179,6 +2185,9 @@
5.73 if not in_pyfunc:
5.74 error(pos, "'not None' only allowed in Python functions")
5.75 not_none = 1
5.76 + if annotated and s.sy == ':':
5.77 + s.next()
5.78 + annotation = p_simple_expr(s)
5.79 if s.sy == '=':
5.80 s.next()
5.81 if 'pxd' in s.level:
5.82 @@ -2193,6 +2202,7 @@
5.83 declarator = declarator,
5.84 not_none = not_none,
5.85 default = default,
5.86 + annotation = annotation,
5.87 kw_only = kw_only)
5.88
5.89 def p_api(s):
5.90 @@ -2458,13 +2468,19 @@
5.91 s.expect(')')
5.92 if p_nogil(s):
5.93 error(s.pos, "Python function cannot be declared nogil")
5.94 + return_type_annotation = None
5.95 + if s.sy == '->':
5.96 + s.next()
5.97 + return_type_annotation = p_simple_expr(s)
5.98 doc, body = p_suite(s, Ctx(level = 'function'), with_doc = 1)
5.99 return Nodes.DefNode(pos, name = name, args = args,
5.100 star_arg = star_arg, starstar_arg = starstar_arg,
5.101 - doc = doc, body = body, decorators = decorators)
5.102 + doc = doc, body = body, decorators = decorators,
5.103 + return_type_annotation = return_type_annotation)
5.104
5.105 -def p_varargslist(s, terminator=')'):
5.106 - args = p_c_arg_list(s, in_pyfunc = 1, nonempty_declarators = 1)
5.107 +def p_varargslist(s, terminator=')', annotated=1):
5.108 + args = p_c_arg_list(s, in_pyfunc = 1, nonempty_declarators = 1,
5.109 + annotated = annotated)
5.110 star_arg = None
5.111 starstar_arg = None
5.112 if s.sy == '*':
5.113 @@ -2485,7 +2501,11 @@
5.114 def p_py_arg_decl(s):
5.115 pos = s.position()
5.116 name = p_ident(s)
5.117 - return Nodes.PyArgDeclNode(pos, name = name)
5.118 + annotation = None
5.119 + if s.sy == ':':
5.120 + s.next()
5.121 + annotation = p_simple_expr(s)
5.122 + return Nodes.PyArgDeclNode(pos, name = name, annotation = annotation)
5.123
5.124 def p_class_statement(s, decorators):
5.125 # s.sy == 'class'
6.1 --- a/Cython/Utils.py Wed Jan 06 11:05:39 2010 -0800
6.2 +++ b/Cython/Utils.py Thu Jan 28 23:05:39 2010 +0100
6.3 @@ -82,16 +82,31 @@
6.4 encoding = detect_file_encoding(source_filename)
6.5 return codecs.open(source_filename, mode=mode, encoding=encoding)
6.6
6.7 +def str_to_number(value):
6.8 + # note: this expects a string as input that was accepted by the
6.9 + # parser already
6.10 + if len(value) < 2:
6.11 + value = int(value, 0)
6.12 + elif value[0] == '0':
6.13 + if value[1] in 'xX':
6.14 + # hex notation ('0x1AF')
6.15 + value = int(value[2:], 16)
6.16 + elif value[1] in 'oO':
6.17 + # Py3 octal notation ('0o136')
6.18 + value = int(value[2:], 8)
6.19 + elif value[1] in 'bB':
6.20 + # Py3 binary notation ('0b101')
6.21 + value = int(value[2:], 2)
6.22 + else:
6.23 + # Py2 octal notation ('0136')
6.24 + value = int(value, 8)
6.25 + else:
6.26 + value = int(value, 0)
6.27 + return value
6.28 +
6.29 def long_literal(value):
6.30 if isinstance(value, basestring):
6.31 - if len(value) < 2:
6.32 - value = int(value)
6.33 - elif value[0] == 0:
6.34 - value = int(value, 8)
6.35 - elif value[1] in 'xX':
6.36 - value = int(value[2:], 16)
6.37 - else:
6.38 - value = int(value)
6.39 + value = str_to_number(value)
6.40 return not -2**31 <= value < 2**31
6.41
6.42 def none_or_sub(s, data):
