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
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):