| Index: third_party/cython/src/Cython/Compiler/Parsing.py
|
| diff --git a/third_party/cython/src/Cython/Compiler/Parsing.py b/third_party/cython/src/Cython/Compiler/Parsing.py
|
| new file mode 100644
|
| index 0000000000000000000000000000000000000000..8b9eadaaf9933a1dc3f2f02dfd1831bb7c947511
|
| --- /dev/null
|
| +++ b/third_party/cython/src/Cython/Compiler/Parsing.py
|
| @@ -0,0 +1,3294 @@
|
| +# cython: auto_cpdef=True, infer_types=True, language_level=3, py2_import=True
|
| +#
|
| +# Parser
|
| +#
|
| +
|
| +# This should be done automatically
|
| +import cython
|
| +cython.declare(Nodes=object, ExprNodes=object, EncodedString=object,
|
| + BytesLiteral=object, StringEncoding=object,
|
| + FileSourceDescriptor=object, lookup_unicodechar=object,
|
| + Future=object, Options=object, error=object, warning=object,
|
| + Builtin=object, ModuleNode=object, Utils=object,
|
| + re=object, _unicode=object, _bytes=object)
|
| +
|
| +import re
|
| +from unicodedata import lookup as lookup_unicodechar
|
| +
|
| +from Cython.Compiler.Scanning import PyrexScanner, FileSourceDescriptor
|
| +import Nodes
|
| +import ExprNodes
|
| +import Builtin
|
| +import StringEncoding
|
| +from StringEncoding import EncodedString, BytesLiteral, _unicode, _bytes
|
| +from ModuleNode import ModuleNode
|
| +from Errors import error, warning
|
| +from Cython import Utils
|
| +import Future
|
| +import Options
|
| +
|
| +class Ctx(object):
|
| + # Parsing context
|
| + level = 'other'
|
| + visibility = 'private'
|
| + cdef_flag = 0
|
| + typedef_flag = 0
|
| + api = 0
|
| + overridable = 0
|
| + nogil = 0
|
| + namespace = None
|
| + templates = None
|
| + allow_struct_enum_decorator = False
|
| +
|
| + def __init__(self, **kwds):
|
| + self.__dict__.update(kwds)
|
| +
|
| + def __call__(self, **kwds):
|
| + ctx = Ctx()
|
| + d = ctx.__dict__
|
| + d.update(self.__dict__)
|
| + d.update(kwds)
|
| + return ctx
|
| +
|
| +def p_ident(s, message = "Expected an identifier"):
|
| + if s.sy == 'IDENT':
|
| + name = s.systring
|
| + s.next()
|
| + return name
|
| + else:
|
| + s.error(message)
|
| +
|
| +def p_ident_list(s):
|
| + names = []
|
| + while s.sy == 'IDENT':
|
| + names.append(s.systring)
|
| + s.next()
|
| + if s.sy != ',':
|
| + break
|
| + s.next()
|
| + return names
|
| +
|
| +#------------------------------------------
|
| +#
|
| +# Expressions
|
| +#
|
| +#------------------------------------------
|
| +
|
| +def p_binop_operator(s):
|
| + pos = s.position()
|
| + op = s.sy
|
| + s.next()
|
| + return op, pos
|
| +
|
| +def p_binop_expr(s, ops, p_sub_expr):
|
| + n1 = p_sub_expr(s)
|
| + while s.sy in ops:
|
| + op, pos = p_binop_operator(s)
|
| + n2 = p_sub_expr(s)
|
| + n1 = ExprNodes.binop_node(pos, op, n1, n2)
|
| + if op == '/':
|
| + if Future.division in s.context.future_directives:
|
| + n1.truedivision = True
|
| + else:
|
| + n1.truedivision = None # unknown
|
| + return n1
|
| +
|
| +#lambdef: 'lambda' [varargslist] ':' test
|
| +
|
| +def p_lambdef(s, allow_conditional=True):
|
| + # s.sy == 'lambda'
|
| + pos = s.position()
|
| + s.next()
|
| + if s.sy == ':':
|
| + args = []
|
| + star_arg = starstar_arg = None
|
| + else:
|
| + args, star_arg, starstar_arg = p_varargslist(
|
| + s, terminator=':', annotated=False)
|
| + s.expect(':')
|
| + if allow_conditional:
|
| + expr = p_test(s)
|
| + else:
|
| + expr = p_test_nocond(s)
|
| + return ExprNodes.LambdaNode(
|
| + pos, args = args,
|
| + star_arg = star_arg, starstar_arg = starstar_arg,
|
| + result_expr = expr)
|
| +
|
| +#lambdef_nocond: 'lambda' [varargslist] ':' test_nocond
|
| +
|
| +def p_lambdef_nocond(s):
|
| + return p_lambdef(s, allow_conditional=False)
|
| +
|
| +#test: or_test ['if' or_test 'else' test] | lambdef
|
| +
|
| +def p_test(s):
|
| + if s.sy == 'lambda':
|
| + return p_lambdef(s)
|
| + pos = s.position()
|
| + expr = p_or_test(s)
|
| + if s.sy == 'if':
|
| + s.next()
|
| + test = p_or_test(s)
|
| + s.expect('else')
|
| + other = p_test(s)
|
| + return ExprNodes.CondExprNode(pos, test=test, true_val=expr, false_val=other)
|
| + else:
|
| + return expr
|
| +
|
| +#test_nocond: or_test | lambdef_nocond
|
| +
|
| +def p_test_nocond(s):
|
| + if s.sy == 'lambda':
|
| + return p_lambdef_nocond(s)
|
| + else:
|
| + return p_or_test(s)
|
| +
|
| +#or_test: and_test ('or' and_test)*
|
| +
|
| +def p_or_test(s):
|
| + return p_rassoc_binop_expr(s, ('or',), p_and_test)
|
| +
|
| +def p_rassoc_binop_expr(s, ops, p_subexpr):
|
| + n1 = p_subexpr(s)
|
| + if s.sy in ops:
|
| + pos = s.position()
|
| + op = s.sy
|
| + s.next()
|
| + n2 = p_rassoc_binop_expr(s, ops, p_subexpr)
|
| + n1 = ExprNodes.binop_node(pos, op, n1, n2)
|
| + return n1
|
| +
|
| +#and_test: not_test ('and' not_test)*
|
| +
|
| +def p_and_test(s):
|
| + #return p_binop_expr(s, ('and',), p_not_test)
|
| + return p_rassoc_binop_expr(s, ('and',), p_not_test)
|
| +
|
| +#not_test: 'not' not_test | comparison
|
| +
|
| +def p_not_test(s):
|
| + if s.sy == 'not':
|
| + pos = s.position()
|
| + s.next()
|
| + return ExprNodes.NotNode(pos, operand = p_not_test(s))
|
| + else:
|
| + return p_comparison(s)
|
| +
|
| +#comparison: expr (comp_op expr)*
|
| +#comp_op: '<'|'>'|'=='|'>='|'<='|'<>'|'!='|'in'|'not' 'in'|'is'|'is' 'not'
|
| +
|
| +def p_comparison(s):
|
| + n1 = p_starred_expr(s)
|
| + if s.sy in comparison_ops:
|
| + pos = s.position()
|
| + op = p_cmp_op(s)
|
| + n2 = p_starred_expr(s)
|
| + n1 = ExprNodes.PrimaryCmpNode(pos,
|
| + operator = op, operand1 = n1, operand2 = n2)
|
| + if s.sy in comparison_ops:
|
| + n1.cascade = p_cascaded_cmp(s)
|
| + return n1
|
| +
|
| +def p_test_or_starred_expr(s):
|
| + if s.sy == '*':
|
| + return p_starred_expr(s)
|
| + else:
|
| + return p_test(s)
|
| +
|
| +def p_starred_expr(s):
|
| + pos = s.position()
|
| + if s.sy == '*':
|
| + starred = True
|
| + s.next()
|
| + else:
|
| + starred = False
|
| + expr = p_bit_expr(s)
|
| + if starred:
|
| + expr = ExprNodes.StarredTargetNode(pos, expr)
|
| + return expr
|
| +
|
| +def p_cascaded_cmp(s):
|
| + pos = s.position()
|
| + op = p_cmp_op(s)
|
| + n2 = p_starred_expr(s)
|
| + result = ExprNodes.CascadedCmpNode(pos,
|
| + operator = op, operand2 = n2)
|
| + if s.sy in comparison_ops:
|
| + result.cascade = p_cascaded_cmp(s)
|
| + return result
|
| +
|
| +def p_cmp_op(s):
|
| + if s.sy == 'not':
|
| + s.next()
|
| + s.expect('in')
|
| + op = 'not_in'
|
| + elif s.sy == 'is':
|
| + s.next()
|
| + if s.sy == 'not':
|
| + s.next()
|
| + op = 'is_not'
|
| + else:
|
| + op = 'is'
|
| + else:
|
| + op = s.sy
|
| + s.next()
|
| + if op == '<>':
|
| + op = '!='
|
| + return op
|
| +
|
| +comparison_ops = cython.declare(set, set([
|
| + '<', '>', '==', '>=', '<=', '<>', '!=',
|
| + 'in', 'is', 'not'
|
| +]))
|
| +
|
| +#expr: xor_expr ('|' xor_expr)*
|
| +
|
| +def p_bit_expr(s):
|
| + return p_binop_expr(s, ('|',), p_xor_expr)
|
| +
|
| +#xor_expr: and_expr ('^' and_expr)*
|
| +
|
| +def p_xor_expr(s):
|
| + return p_binop_expr(s, ('^',), p_and_expr)
|
| +
|
| +#and_expr: shift_expr ('&' shift_expr)*
|
| +
|
| +def p_and_expr(s):
|
| + return p_binop_expr(s, ('&',), p_shift_expr)
|
| +
|
| +#shift_expr: arith_expr (('<<'|'>>') arith_expr)*
|
| +
|
| +def p_shift_expr(s):
|
| + return p_binop_expr(s, ('<<', '>>'), p_arith_expr)
|
| +
|
| +#arith_expr: term (('+'|'-') term)*
|
| +
|
| +def p_arith_expr(s):
|
| + return p_binop_expr(s, ('+', '-'), p_term)
|
| +
|
| +#term: factor (('*'|'/'|'%') factor)*
|
| +
|
| +def p_term(s):
|
| + return p_binop_expr(s, ('*', '/', '%', '//'), p_factor)
|
| +
|
| +#factor: ('+'|'-'|'~'|'&'|typecast|sizeof) factor | power
|
| +
|
| +def p_factor(s):
|
| + # little indirection for C-ification purposes
|
| + return _p_factor(s)
|
| +
|
| +def _p_factor(s):
|
| + sy = s.sy
|
| + if sy in ('+', '-', '~'):
|
| + op = s.sy
|
| + pos = s.position()
|
| + s.next()
|
| + return ExprNodes.unop_node(pos, op, p_factor(s))
|
| + elif not s.in_python_file:
|
| + if sy == '&':
|
| + pos = s.position()
|
| + s.next()
|
| + arg = p_factor(s)
|
| + return ExprNodes.AmpersandNode(pos, operand = arg)
|
| + elif sy == "<":
|
| + return p_typecast(s)
|
| + elif sy == 'IDENT' and s.systring == "sizeof":
|
| + return p_sizeof(s)
|
| + return p_power(s)
|
| +
|
| +def p_typecast(s):
|
| + # s.sy == "<"
|
| + pos = s.position()
|
| + s.next()
|
| + base_type = p_c_base_type(s)
|
| + is_memslice = isinstance(base_type, Nodes.MemoryViewSliceTypeNode)
|
| + is_template = isinstance(base_type, Nodes.TemplatedTypeNode)
|
| + is_const = isinstance(base_type, Nodes.CConstTypeNode)
|
| + if (not is_memslice and not is_template and not is_const
|
| + and base_type.name is None):
|
| + s.error("Unknown type")
|
| + declarator = p_c_declarator(s, empty = 1)
|
| + if s.sy == '?':
|
| + s.next()
|
| + typecheck = 1
|
| + else:
|
| + typecheck = 0
|
| + s.expect(">")
|
| + operand = p_factor(s)
|
| + if is_memslice:
|
| + return ExprNodes.CythonArrayNode(pos, base_type_node=base_type,
|
| + operand=operand)
|
| +
|
| + return ExprNodes.TypecastNode(pos,
|
| + base_type = base_type,
|
| + declarator = declarator,
|
| + operand = operand,
|
| + typecheck = typecheck)
|
| +
|
| +def p_sizeof(s):
|
| + # s.sy == ident "sizeof"
|
| + pos = s.position()
|
| + s.next()
|
| + s.expect('(')
|
| + # Here we decide if we are looking at an expression or type
|
| + # If it is actually a type, but parsable as an expression,
|
| + # we treat it as an expression here.
|
| + if looking_at_expr(s):
|
| + operand = p_test(s)
|
| + node = ExprNodes.SizeofVarNode(pos, operand = operand)
|
| + else:
|
| + base_type = p_c_base_type(s)
|
| + declarator = p_c_declarator(s, empty = 1)
|
| + node = ExprNodes.SizeofTypeNode(pos,
|
| + base_type = base_type, declarator = declarator)
|
| + s.expect(')')
|
| + return node
|
| +
|
| +def p_yield_expression(s):
|
| + # s.sy == "yield"
|
| + pos = s.position()
|
| + s.next()
|
| + is_yield_from = False
|
| + if s.sy == 'from':
|
| + is_yield_from = True
|
| + s.next()
|
| + if s.sy != ')' and s.sy not in statement_terminators:
|
| + arg = p_testlist(s)
|
| + else:
|
| + if is_yield_from:
|
| + s.error("'yield from' requires a source argument",
|
| + pos=pos, fatal=False)
|
| + arg = None
|
| + if is_yield_from:
|
| + return ExprNodes.YieldFromExprNode(pos, arg=arg)
|
| + else:
|
| + return ExprNodes.YieldExprNode(pos, arg=arg)
|
| +
|
| +def p_yield_statement(s):
|
| + # s.sy == "yield"
|
| + yield_expr = p_yield_expression(s)
|
| + return Nodes.ExprStatNode(yield_expr.pos, expr=yield_expr)
|
| +
|
| +#power: atom trailer* ('**' factor)*
|
| +
|
| +def p_power(s):
|
| + if s.systring == 'new' and s.peek()[0] == 'IDENT':
|
| + return p_new_expr(s)
|
| + n1 = p_atom(s)
|
| + while s.sy in ('(', '[', '.'):
|
| + n1 = p_trailer(s, n1)
|
| + if s.sy == '**':
|
| + pos = s.position()
|
| + s.next()
|
| + n2 = p_factor(s)
|
| + n1 = ExprNodes.binop_node(pos, '**', n1, n2)
|
| + return n1
|
| +
|
| +def p_new_expr(s):
|
| + # s.systring == 'new'.
|
| + pos = s.position()
|
| + s.next()
|
| + cppclass = p_c_base_type(s)
|
| + return p_call(s, ExprNodes.NewExprNode(pos, cppclass = cppclass))
|
| +
|
| +#trailer: '(' [arglist] ')' | '[' subscriptlist ']' | '.' NAME
|
| +
|
| +def p_trailer(s, node1):
|
| + pos = s.position()
|
| + if s.sy == '(':
|
| + return p_call(s, node1)
|
| + elif s.sy == '[':
|
| + return p_index(s, node1)
|
| + else: # s.sy == '.'
|
| + s.next()
|
| + name = EncodedString( p_ident(s) )
|
| + return ExprNodes.AttributeNode(pos,
|
| + obj = node1, attribute = name)
|
| +
|
| +# arglist: argument (',' argument)* [',']
|
| +# argument: [test '='] test # Really [keyword '='] test
|
| +
|
| +def p_call_parse_args(s, allow_genexp = True):
|
| + # s.sy == '('
|
| + pos = s.position()
|
| + s.next()
|
| + positional_args = []
|
| + keyword_args = []
|
| + star_arg = None
|
| + starstar_arg = None
|
| + while s.sy not in ('**', ')'):
|
| + if s.sy == '*':
|
| + if star_arg:
|
| + s.error("only one star-arg parameter allowed",
|
| + pos=s.position())
|
| + s.next()
|
| + star_arg = p_test(s)
|
| + else:
|
| + arg = p_test(s)
|
| + if s.sy == '=':
|
| + s.next()
|
| + if not arg.is_name:
|
| + s.error("Expected an identifier before '='",
|
| + pos=arg.pos)
|
| + encoded_name = EncodedString(arg.name)
|
| + keyword = ExprNodes.IdentifierStringNode(
|
| + arg.pos, value=encoded_name)
|
| + arg = p_test(s)
|
| + keyword_args.append((keyword, arg))
|
| + else:
|
| + if keyword_args:
|
| + s.error("Non-keyword arg following keyword arg",
|
| + pos=arg.pos)
|
| + if star_arg:
|
| + s.error("Non-keyword arg following star-arg",
|
| + pos=arg.pos)
|
| + positional_args.append(arg)
|
| + if s.sy != ',':
|
| + break
|
| + s.next()
|
| +
|
| + if s.sy == 'for':
|
| + if len(positional_args) == 1 and not star_arg:
|
| + positional_args = [ p_genexp(s, positional_args[0]) ]
|
| + elif s.sy == '**':
|
| + s.next()
|
| + starstar_arg = p_test(s)
|
| + if s.sy == ',':
|
| + s.next()
|
| + s.expect(')')
|
| + return positional_args, keyword_args, star_arg, starstar_arg
|
| +
|
| +def p_call_build_packed_args(pos, positional_args, keyword_args,
|
| + star_arg, starstar_arg):
|
| + arg_tuple = None
|
| + keyword_dict = None
|
| + if positional_args or not star_arg:
|
| + arg_tuple = ExprNodes.TupleNode(pos,
|
| + args = positional_args)
|
| + if star_arg:
|
| + star_arg_tuple = ExprNodes.AsTupleNode(pos, arg = star_arg)
|
| + if arg_tuple:
|
| + arg_tuple = ExprNodes.binop_node(pos,
|
| + operator = '+', operand1 = arg_tuple,
|
| + operand2 = star_arg_tuple)
|
| + else:
|
| + arg_tuple = star_arg_tuple
|
| + if keyword_args or starstar_arg:
|
| + keyword_args = [ExprNodes.DictItemNode(pos=key.pos, key=key, value=value)
|
| + for key, value in keyword_args]
|
| + if starstar_arg:
|
| + keyword_dict = ExprNodes.KeywordArgsNode(
|
| + pos,
|
| + starstar_arg = starstar_arg,
|
| + keyword_args = keyword_args)
|
| + else:
|
| + keyword_dict = ExprNodes.DictNode(
|
| + pos, key_value_pairs = keyword_args)
|
| + return arg_tuple, keyword_dict
|
| +
|
| +def p_call(s, function):
|
| + # s.sy == '('
|
| + pos = s.position()
|
| +
|
| + positional_args, keyword_args, star_arg, starstar_arg = \
|
| + p_call_parse_args(s)
|
| +
|
| + if not (keyword_args or star_arg or starstar_arg):
|
| + return ExprNodes.SimpleCallNode(pos,
|
| + function = function,
|
| + args = positional_args)
|
| + else:
|
| + arg_tuple, keyword_dict = p_call_build_packed_args(
|
| + pos, positional_args, keyword_args, star_arg, starstar_arg)
|
| + return ExprNodes.GeneralCallNode(pos,
|
| + function = function,
|
| + positional_args = arg_tuple,
|
| + keyword_args = keyword_dict)
|
| +
|
| +#lambdef: 'lambda' [varargslist] ':' test
|
| +
|
| +#subscriptlist: subscript (',' subscript)* [',']
|
| +
|
| +def p_index(s, base):
|
| + # s.sy == '['
|
| + pos = s.position()
|
| + s.next()
|
| + subscripts, is_single_value = p_subscript_list(s)
|
| + if is_single_value and len(subscripts[0]) == 2:
|
| + start, stop = subscripts[0]
|
| + result = ExprNodes.SliceIndexNode(pos,
|
| + base = base, start = start, stop = stop)
|
| + else:
|
| + indexes = make_slice_nodes(pos, subscripts)
|
| + if is_single_value:
|
| + index = indexes[0]
|
| + else:
|
| + index = ExprNodes.TupleNode(pos, args = indexes)
|
| + result = ExprNodes.IndexNode(pos,
|
| + base = base, index = index)
|
| + s.expect(']')
|
| + return result
|
| +
|
| +def p_subscript_list(s):
|
| + is_single_value = True
|
| + items = [p_subscript(s)]
|
| + while s.sy == ',':
|
| + is_single_value = False
|
| + s.next()
|
| + if s.sy == ']':
|
| + break
|
| + items.append(p_subscript(s))
|
| + return items, is_single_value
|
| +
|
| +#subscript: '.' '.' '.' | test | [test] ':' [test] [':' [test]]
|
| +
|
| +def p_subscript(s):
|
| + # Parse a subscript and return a list of
|
| + # 1, 2 or 3 ExprNodes, depending on how
|
| + # many slice elements were encountered.
|
| + pos = s.position()
|
| + start = p_slice_element(s, (':',))
|
| + if s.sy != ':':
|
| + return [start]
|
| + s.next()
|
| + stop = p_slice_element(s, (':', ',', ']'))
|
| + if s.sy != ':':
|
| + return [start, stop]
|
| + s.next()
|
| + step = p_slice_element(s, (':', ',', ']'))
|
| + return [start, stop, step]
|
| +
|
| +def p_slice_element(s, follow_set):
|
| + # Simple expression which may be missing iff
|
| + # it is followed by something in follow_set.
|
| + if s.sy not in follow_set:
|
| + return p_test(s)
|
| + else:
|
| + return None
|
| +
|
| +def expect_ellipsis(s):
|
| + s.expect('.')
|
| + s.expect('.')
|
| + s.expect('.')
|
| +
|
| +def make_slice_nodes(pos, subscripts):
|
| + # Convert a list of subscripts as returned
|
| + # by p_subscript_list into a list of ExprNodes,
|
| + # creating SliceNodes for elements with 2 or
|
| + # more components.
|
| + result = []
|
| + for subscript in subscripts:
|
| + if len(subscript) == 1:
|
| + result.append(subscript[0])
|
| + else:
|
| + result.append(make_slice_node(pos, *subscript))
|
| + return result
|
| +
|
| +def make_slice_node(pos, start, stop = None, step = None):
|
| + if not start:
|
| + start = ExprNodes.NoneNode(pos)
|
| + if not stop:
|
| + stop = ExprNodes.NoneNode(pos)
|
| + if not step:
|
| + step = ExprNodes.NoneNode(pos)
|
| + return ExprNodes.SliceNode(pos,
|
| + start = start, stop = stop, step = step)
|
| +
|
| +#atom: '(' [yield_expr|testlist_comp] ')' | '[' [listmaker] ']' | '{' [dict_or_set_maker] '}' | '`' testlist '`' | NAME | NUMBER | STRING+
|
| +
|
| +def p_atom(s):
|
| + pos = s.position()
|
| + sy = s.sy
|
| + if sy == '(':
|
| + s.next()
|
| + if s.sy == ')':
|
| + result = ExprNodes.TupleNode(pos, args = [])
|
| + elif s.sy == 'yield':
|
| + result = p_yield_expression(s)
|
| + else:
|
| + result = p_testlist_comp(s)
|
| + s.expect(')')
|
| + return result
|
| + elif sy == '[':
|
| + return p_list_maker(s)
|
| + elif sy == '{':
|
| + return p_dict_or_set_maker(s)
|
| + elif sy == '`':
|
| + return p_backquote_expr(s)
|
| + elif sy == '.':
|
| + expect_ellipsis(s)
|
| + return ExprNodes.EllipsisNode(pos)
|
| + elif sy == 'INT':
|
| + return p_int_literal(s)
|
| + elif sy == 'FLOAT':
|
| + value = s.systring
|
| + s.next()
|
| + return ExprNodes.FloatNode(pos, value = value)
|
| + elif sy == 'IMAG':
|
| + value = s.systring[:-1]
|
| + s.next()
|
| + return ExprNodes.ImagNode(pos, value = value)
|
| + elif sy == 'BEGIN_STRING':
|
| + kind, bytes_value, unicode_value = p_cat_string_literal(s)
|
| + if kind == 'c':
|
| + return ExprNodes.CharNode(pos, value = bytes_value)
|
| + elif kind == 'u':
|
| + return ExprNodes.UnicodeNode(pos, value = unicode_value, bytes_value = bytes_value)
|
| + elif kind == 'b':
|
| + return ExprNodes.BytesNode(pos, value = bytes_value)
|
| + else:
|
| + return ExprNodes.StringNode(pos, value = bytes_value, unicode_value = unicode_value)
|
| + elif sy == 'IDENT':
|
| + name = EncodedString( s.systring )
|
| + s.next()
|
| + if name == "None":
|
| + return ExprNodes.NoneNode(pos)
|
| + elif name == "True":
|
| + return ExprNodes.BoolNode(pos, value=True)
|
| + elif name == "False":
|
| + return ExprNodes.BoolNode(pos, value=False)
|
| + elif name == "NULL" and not s.in_python_file:
|
| + return ExprNodes.NullNode(pos)
|
| + else:
|
| + return p_name(s, name)
|
| + else:
|
| + s.error("Expected an identifier or literal")
|
| +
|
| +def p_int_literal(s):
|
| + pos = s.position()
|
| + value = s.systring
|
| + s.next()
|
| + unsigned = ""
|
| + longness = ""
|
| + while value[-1] in u"UuLl":
|
| + if value[-1] in u"Ll":
|
| + longness += "L"
|
| + else:
|
| + unsigned += "U"
|
| + value = value[:-1]
|
| + # '3L' is ambiguous in Py2 but not in Py3. '3U' and '3LL' are
|
| + # illegal in Py2 Python files. All suffixes are illegal in Py3
|
| + # Python files.
|
| + is_c_literal = None
|
| + if unsigned:
|
| + is_c_literal = True
|
| + elif longness:
|
| + if longness == 'LL' or s.context.language_level >= 3:
|
| + is_c_literal = True
|
| + if s.in_python_file:
|
| + if is_c_literal:
|
| + error(pos, "illegal integer literal syntax in Python source file")
|
| + is_c_literal = False
|
| + return ExprNodes.IntNode(pos,
|
| + is_c_literal = is_c_literal,
|
| + value = value,
|
| + unsigned = unsigned,
|
| + longness = longness)
|
| +
|
| +
|
| +def p_name(s, name):
|
| + pos = s.position()
|
| + if not s.compile_time_expr and name in s.compile_time_env:
|
| + value = s.compile_time_env.lookup_here(name)
|
| + node = wrap_compile_time_constant(pos, value)
|
| + if node is not None:
|
| + return node
|
| + return ExprNodes.NameNode(pos, name=name)
|
| +
|
| +
|
| +def wrap_compile_time_constant(pos, value):
|
| + rep = repr(value)
|
| + if value is None:
|
| + return ExprNodes.NoneNode(pos)
|
| + elif value is Ellipsis:
|
| + return ExprNodes.EllipsisNode(pos)
|
| + elif isinstance(value, bool):
|
| + return ExprNodes.BoolNode(pos, value=value)
|
| + elif isinstance(value, int):
|
| + return ExprNodes.IntNode(pos, value=rep)
|
| + elif isinstance(value, long):
|
| + return ExprNodes.IntNode(pos, value=rep, longness="L")
|
| + elif isinstance(value, float):
|
| + return ExprNodes.FloatNode(pos, value=rep)
|
| + elif isinstance(value, _unicode):
|
| + return ExprNodes.UnicodeNode(pos, value=EncodedString(value))
|
| + elif isinstance(value, _bytes):
|
| + return ExprNodes.BytesNode(pos, value=BytesLiteral(value))
|
| + elif isinstance(value, tuple):
|
| + args = [wrap_compile_time_constant(pos, arg)
|
| + for arg in value]
|
| + if None not in args:
|
| + return ExprNodes.TupleNode(pos, args=args)
|
| + else:
|
| + # error already reported
|
| + return None
|
| + error(pos, "Invalid type for compile-time constant: %r (type %s)"
|
| + % (value, value.__class__.__name__))
|
| + return None
|
| +
|
| +
|
| +def p_cat_string_literal(s):
|
| + # A sequence of one or more adjacent string literals.
|
| + # Returns (kind, bytes_value, unicode_value)
|
| + # where kind in ('b', 'c', 'u', '')
|
| + kind, bytes_value, unicode_value = p_string_literal(s)
|
| + if kind == 'c' or s.sy != 'BEGIN_STRING':
|
| + return kind, bytes_value, unicode_value
|
| + bstrings, ustrings = [bytes_value], [unicode_value]
|
| + bytes_value = unicode_value = None
|
| + while s.sy == 'BEGIN_STRING':
|
| + pos = s.position()
|
| + next_kind, next_bytes_value, next_unicode_value = p_string_literal(s)
|
| + if next_kind == 'c':
|
| + error(pos, "Cannot concatenate char literal with another string or char literal")
|
| + elif next_kind != kind:
|
| + error(pos, "Cannot mix string literals of different types, expected %s'', got %s''" %
|
| + (kind, next_kind))
|
| + else:
|
| + bstrings.append(next_bytes_value)
|
| + ustrings.append(next_unicode_value)
|
| + # join and rewrap the partial literals
|
| + if kind in ('b', 'c', '') or kind == 'u' and None not in bstrings:
|
| + # Py3 enforced unicode literals are parsed as bytes/unicode combination
|
| + bytes_value = BytesLiteral( StringEncoding.join_bytes(bstrings) )
|
| + bytes_value.encoding = s.source_encoding
|
| + if kind in ('u', ''):
|
| + unicode_value = EncodedString( u''.join([ u for u in ustrings if u is not None ]) )
|
| + return kind, bytes_value, unicode_value
|
| +
|
| +def p_opt_string_literal(s, required_type='u'):
|
| + if s.sy == 'BEGIN_STRING':
|
| + kind, bytes_value, unicode_value = p_string_literal(s, required_type)
|
| + if required_type == 'u':
|
| + return unicode_value
|
| + elif required_type == 'b':
|
| + return bytes_value
|
| + else:
|
| + s.error("internal parser configuration error")
|
| + else:
|
| + return None
|
| +
|
| +def check_for_non_ascii_characters(string):
|
| + for c in string:
|
| + if c >= u'\x80':
|
| + return True
|
| + return False
|
| +
|
| +def p_string_literal(s, kind_override=None):
|
| + # A single string or char literal. Returns (kind, bvalue, uvalue)
|
| + # where kind in ('b', 'c', 'u', ''). The 'bvalue' is the source
|
| + # code byte sequence of the string literal, 'uvalue' is the
|
| + # decoded Unicode string. Either of the two may be None depending
|
| + # on the 'kind' of string, only unprefixed strings have both
|
| + # representations.
|
| +
|
| + # s.sy == 'BEGIN_STRING'
|
| + pos = s.position()
|
| + is_raw = False
|
| + is_python3_source = s.context.language_level >= 3
|
| + has_non_ASCII_literal_characters = False
|
| + kind = s.systring[:1].lower()
|
| + if kind == 'r':
|
| + # Py3 allows both 'br' and 'rb' as prefix
|
| + if s.systring[1:2].lower() == 'b':
|
| + kind = 'b'
|
| + else:
|
| + kind = ''
|
| + is_raw = True
|
| + elif kind in 'ub':
|
| + is_raw = s.systring[1:2].lower() == 'r'
|
| + elif kind != 'c':
|
| + kind = ''
|
| + if kind == '' and kind_override is None and Future.unicode_literals in s.context.future_directives:
|
| + chars = StringEncoding.StrLiteralBuilder(s.source_encoding)
|
| + kind = 'u'
|
| + else:
|
| + if kind_override is not None and kind_override in 'ub':
|
| + kind = kind_override
|
| + if kind == 'u':
|
| + chars = StringEncoding.UnicodeLiteralBuilder()
|
| + elif kind == '':
|
| + chars = StringEncoding.StrLiteralBuilder(s.source_encoding)
|
| + else:
|
| + chars = StringEncoding.BytesLiteralBuilder(s.source_encoding)
|
| +
|
| + while 1:
|
| + s.next()
|
| + sy = s.sy
|
| + systr = s.systring
|
| + #print "p_string_literal: sy =", sy, repr(s.systring) ###
|
| + if sy == 'CHARS':
|
| + chars.append(systr)
|
| + if is_python3_source and not has_non_ASCII_literal_characters and check_for_non_ascii_characters(systr):
|
| + has_non_ASCII_literal_characters = True
|
| + elif sy == 'ESCAPE':
|
| + if is_raw:
|
| + chars.append(systr)
|
| + if is_python3_source and not has_non_ASCII_literal_characters \
|
| + and check_for_non_ascii_characters(systr):
|
| + has_non_ASCII_literal_characters = True
|
| + else:
|
| + c = systr[1]
|
| + if c in u"01234567":
|
| + chars.append_charval( int(systr[1:], 8) )
|
| + elif c in u"'\"\\":
|
| + chars.append(c)
|
| + elif c in u"abfnrtv":
|
| + chars.append(
|
| + StringEncoding.char_from_escape_sequence(systr))
|
| + elif c == u'\n':
|
| + pass
|
| + elif c == u'x': # \xXX
|
| + if len(systr) == 4:
|
| + chars.append_charval( int(systr[2:], 16) )
|
| + else:
|
| + s.error("Invalid hex escape '%s'" % systr,
|
| + fatal=False)
|
| + elif c in u'NUu' and kind in ('u', ''): # \uxxxx, \Uxxxxxxxx, \N{...}
|
| + chrval = -1
|
| + if c == u'N':
|
| + try:
|
| + chrval = ord(lookup_unicodechar(systr[3:-1]))
|
| + except KeyError:
|
| + s.error("Unknown Unicode character name %s" %
|
| + repr(systr[3:-1]).lstrip('u'))
|
| + elif len(systr) in (6,10):
|
| + chrval = int(systr[2:], 16)
|
| + if chrval > 1114111: # sys.maxunicode:
|
| + s.error("Invalid unicode escape '%s'" % systr)
|
| + chrval = -1
|
| + else:
|
| + s.error("Invalid unicode escape '%s'" % systr,
|
| + fatal=False)
|
| + if chrval >= 0:
|
| + chars.append_uescape(chrval, systr)
|
| + else:
|
| + chars.append(u'\\' + systr[1:])
|
| + if is_python3_source and not has_non_ASCII_literal_characters \
|
| + and check_for_non_ascii_characters(systr):
|
| + has_non_ASCII_literal_characters = True
|
| + elif sy == 'NEWLINE':
|
| + chars.append(u'\n')
|
| + elif sy == 'END_STRING':
|
| + break
|
| + elif sy == 'EOF':
|
| + s.error("Unclosed string literal", pos=pos)
|
| + else:
|
| + s.error("Unexpected token %r:%r in string literal" %
|
| + (sy, s.systring))
|
| +
|
| + if kind == 'c':
|
| + unicode_value = None
|
| + bytes_value = chars.getchar()
|
| + if len(bytes_value) != 1:
|
| + error(pos, u"invalid character literal: %r" % bytes_value)
|
| + else:
|
| + bytes_value, unicode_value = chars.getstrings()
|
| + if is_python3_source and has_non_ASCII_literal_characters:
|
| + # Python 3 forbids literal non-ASCII characters in byte strings
|
| + if kind != 'u':
|
| + s.error("bytes can only contain ASCII literal characters.",
|
| + pos=pos, fatal=False)
|
| + bytes_value = None
|
| + s.next()
|
| + return (kind, bytes_value, unicode_value)
|
| +
|
| +# list_display ::= "[" [listmaker] "]"
|
| +# listmaker ::= expression ( comp_for | ( "," expression )* [","] )
|
| +# comp_iter ::= comp_for | comp_if
|
| +# comp_for ::= "for" expression_list "in" testlist [comp_iter]
|
| +# comp_if ::= "if" test [comp_iter]
|
| +
|
| +def p_list_maker(s):
|
| + # s.sy == '['
|
| + pos = s.position()
|
| + s.next()
|
| + if s.sy == ']':
|
| + s.expect(']')
|
| + return ExprNodes.ListNode(pos, args = [])
|
| + expr = p_test(s)
|
| + if s.sy == 'for':
|
| + append = ExprNodes.ComprehensionAppendNode(pos, expr=expr)
|
| + loop = p_comp_for(s, append)
|
| + s.expect(']')
|
| + return ExprNodes.ComprehensionNode(
|
| + pos, loop=loop, append=append, type = Builtin.list_type,
|
| + # list comprehensions leak their loop variable in Py2
|
| + has_local_scope = s.context.language_level >= 3)
|
| + else:
|
| + if s.sy == ',':
|
| + s.next()
|
| + exprs = p_simple_expr_list(s, expr)
|
| + else:
|
| + exprs = [expr]
|
| + s.expect(']')
|
| + return ExprNodes.ListNode(pos, args = exprs)
|
| +
|
| +def p_comp_iter(s, body):
|
| + if s.sy == 'for':
|
| + return p_comp_for(s, body)
|
| + elif s.sy == 'if':
|
| + return p_comp_if(s, body)
|
| + else:
|
| + # insert the 'append' operation into the loop
|
| + return body
|
| +
|
| +def p_comp_for(s, body):
|
| + # s.sy == 'for'
|
| + pos = s.position()
|
| + s.next()
|
| + kw = p_for_bounds(s, allow_testlist=False)
|
| + kw.update(else_clause = None, body = p_comp_iter(s, body))
|
| + return Nodes.ForStatNode(pos, **kw)
|
| +
|
| +def p_comp_if(s, body):
|
| + # s.sy == 'if'
|
| + pos = s.position()
|
| + s.next()
|
| + test = p_test_nocond(s)
|
| + return Nodes.IfStatNode(pos,
|
| + if_clauses = [Nodes.IfClauseNode(pos, condition = test,
|
| + body = p_comp_iter(s, body))],
|
| + else_clause = None )
|
| +
|
| +#dictmaker: test ':' test (',' test ':' test)* [',']
|
| +
|
| +def p_dict_or_set_maker(s):
|
| + # s.sy == '{'
|
| + pos = s.position()
|
| + s.next()
|
| + if s.sy == '}':
|
| + s.next()
|
| + return ExprNodes.DictNode(pos, key_value_pairs = [])
|
| + item = p_test(s)
|
| + if s.sy == ',' or s.sy == '}':
|
| + # set literal
|
| + values = [item]
|
| + while s.sy == ',':
|
| + s.next()
|
| + if s.sy == '}':
|
| + break
|
| + values.append( p_test(s) )
|
| + s.expect('}')
|
| + return ExprNodes.SetNode(pos, args=values)
|
| + elif s.sy == 'for':
|
| + # set comprehension
|
| + append = ExprNodes.ComprehensionAppendNode(
|
| + item.pos, expr=item)
|
| + loop = p_comp_for(s, append)
|
| + s.expect('}')
|
| + return ExprNodes.ComprehensionNode(
|
| + pos, loop=loop, append=append, type=Builtin.set_type)
|
| + elif s.sy == ':':
|
| + # dict literal or comprehension
|
| + key = item
|
| + s.next()
|
| + value = p_test(s)
|
| + if s.sy == 'for':
|
| + # dict comprehension
|
| + append = ExprNodes.DictComprehensionAppendNode(
|
| + item.pos, key_expr=key, value_expr=value)
|
| + loop = p_comp_for(s, append)
|
| + s.expect('}')
|
| + return ExprNodes.ComprehensionNode(
|
| + pos, loop=loop, append=append, type=Builtin.dict_type)
|
| + else:
|
| + # dict literal
|
| + items = [ExprNodes.DictItemNode(key.pos, key=key, value=value)]
|
| + while s.sy == ',':
|
| + s.next()
|
| + if s.sy == '}':
|
| + break
|
| + key = p_test(s)
|
| + s.expect(':')
|
| + value = p_test(s)
|
| + items.append(
|
| + ExprNodes.DictItemNode(key.pos, key=key, value=value))
|
| + s.expect('}')
|
| + return ExprNodes.DictNode(pos, key_value_pairs=items)
|
| + else:
|
| + # raise an error
|
| + s.expect('}')
|
| + return ExprNodes.DictNode(pos, key_value_pairs = [])
|
| +
|
| +# NOTE: no longer in Py3 :)
|
| +def p_backquote_expr(s):
|
| + # s.sy == '`'
|
| + pos = s.position()
|
| + s.next()
|
| + args = [p_test(s)]
|
| + while s.sy == ',':
|
| + s.next()
|
| + args.append(p_test(s))
|
| + s.expect('`')
|
| + if len(args) == 1:
|
| + arg = args[0]
|
| + else:
|
| + arg = ExprNodes.TupleNode(pos, args = args)
|
| + return ExprNodes.BackquoteNode(pos, arg = arg)
|
| +
|
| +def p_simple_expr_list(s, expr=None):
|
| + exprs = expr is not None and [expr] or []
|
| + while s.sy not in expr_terminators:
|
| + exprs.append( p_test(s) )
|
| + if s.sy != ',':
|
| + break
|
| + s.next()
|
| + return exprs
|
| +
|
| +def p_test_or_starred_expr_list(s, expr=None):
|
| + exprs = expr is not None and [expr] or []
|
| + while s.sy not in expr_terminators:
|
| + exprs.append( p_test_or_starred_expr(s) )
|
| + if s.sy != ',':
|
| + break
|
| + s.next()
|
| + return exprs
|
| +
|
| +
|
| +#testlist: test (',' test)* [',']
|
| +
|
| +def p_testlist(s):
|
| + pos = s.position()
|
| + expr = p_test(s)
|
| + if s.sy == ',':
|
| + s.next()
|
| + exprs = p_simple_expr_list(s, expr)
|
| + return ExprNodes.TupleNode(pos, args = exprs)
|
| + else:
|
| + return expr
|
| +
|
| +# testlist_star_expr: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
|
| +
|
| +def p_testlist_star_expr(s):
|
| + pos = s.position()
|
| + expr = p_test_or_starred_expr(s)
|
| + if s.sy == ',':
|
| + s.next()
|
| + exprs = p_test_or_starred_expr_list(s, expr)
|
| + return ExprNodes.TupleNode(pos, args = exprs)
|
| + else:
|
| + return expr
|
| +
|
| +# testlist_comp: (test|star_expr) ( comp_for | (',' (test|star_expr))* [','] )
|
| +
|
| +def p_testlist_comp(s):
|
| + pos = s.position()
|
| + expr = p_test_or_starred_expr(s)
|
| + if s.sy == ',':
|
| + s.next()
|
| + exprs = p_test_or_starred_expr_list(s, expr)
|
| + return ExprNodes.TupleNode(pos, args = exprs)
|
| + elif s.sy == 'for':
|
| + return p_genexp(s, expr)
|
| + else:
|
| + return expr
|
| +
|
| +def p_genexp(s, expr):
|
| + # s.sy == 'for'
|
| + loop = p_comp_for(s, Nodes.ExprStatNode(
|
| + expr.pos, expr = ExprNodes.YieldExprNode(expr.pos, arg=expr)))
|
| + return ExprNodes.GeneratorExpressionNode(expr.pos, loop=loop)
|
| +
|
| +expr_terminators = cython.declare(set, set([
|
| + ')', ']', '}', ':', '=', 'NEWLINE']))
|
| +
|
| +#-------------------------------------------------------
|
| +#
|
| +# Statements
|
| +#
|
| +#-------------------------------------------------------
|
| +
|
| +def p_global_statement(s):
|
| + # assume s.sy == 'global'
|
| + pos = s.position()
|
| + s.next()
|
| + names = p_ident_list(s)
|
| + return Nodes.GlobalNode(pos, names = names)
|
| +
|
| +def p_nonlocal_statement(s):
|
| + pos = s.position()
|
| + s.next()
|
| + names = p_ident_list(s)
|
| + return Nodes.NonlocalNode(pos, names = names)
|
| +
|
| +def p_expression_or_assignment(s):
|
| + expr_list = [p_testlist_star_expr(s)]
|
| + if s.sy == '=' and expr_list[0].is_starred:
|
| + # This is a common enough error to make when learning Cython to let
|
| + # it fail as early as possible and give a very clear error message.
|
| + s.error("a starred assignment target must be in a list or tuple"
|
| + " - maybe you meant to use an index assignment: var[0] = ...",
|
| + pos=expr_list[0].pos)
|
| + while s.sy == '=':
|
| + s.next()
|
| + if s.sy == 'yield':
|
| + expr = p_yield_expression(s)
|
| + else:
|
| + expr = p_testlist_star_expr(s)
|
| + expr_list.append(expr)
|
| + if len(expr_list) == 1:
|
| + if re.match(r"([+*/\%^\&|-]|<<|>>|\*\*|//)=", s.sy):
|
| + lhs = expr_list[0]
|
| + if isinstance(lhs, ExprNodes.SliceIndexNode):
|
| + # implementation requires IndexNode
|
| + lhs = ExprNodes.IndexNode(
|
| + lhs.pos,
|
| + base=lhs.base,
|
| + index=make_slice_node(lhs.pos, lhs.start, lhs.stop))
|
| + elif not isinstance(lhs, (ExprNodes.AttributeNode, ExprNodes.IndexNode, ExprNodes.NameNode) ):
|
| + error(lhs.pos, "Illegal operand for inplace operation.")
|
| + operator = s.sy[:-1]
|
| + s.next()
|
| + if s.sy == 'yield':
|
| + rhs = p_yield_expression(s)
|
| + else:
|
| + rhs = p_testlist(s)
|
| + return Nodes.InPlaceAssignmentNode(lhs.pos, operator = operator, lhs = lhs, rhs = rhs)
|
| + expr = expr_list[0]
|
| + return Nodes.ExprStatNode(expr.pos, expr=expr)
|
| +
|
| + rhs = expr_list[-1]
|
| + if len(expr_list) == 2:
|
| + return Nodes.SingleAssignmentNode(rhs.pos,
|
| + lhs = expr_list[0], rhs = rhs)
|
| + else:
|
| + return Nodes.CascadedAssignmentNode(rhs.pos,
|
| + lhs_list = expr_list[:-1], rhs = rhs)
|
| +
|
| +def p_print_statement(s):
|
| + # s.sy == 'print'
|
| + pos = s.position()
|
| + ends_with_comma = 0
|
| + s.next()
|
| + if s.sy == '>>':
|
| + s.next()
|
| + stream = p_test(s)
|
| + if s.sy == ',':
|
| + s.next()
|
| + ends_with_comma = s.sy in ('NEWLINE', 'EOF')
|
| + else:
|
| + stream = None
|
| + args = []
|
| + if s.sy not in ('NEWLINE', 'EOF'):
|
| + args.append(p_test(s))
|
| + while s.sy == ',':
|
| + s.next()
|
| + if s.sy in ('NEWLINE', 'EOF'):
|
| + ends_with_comma = 1
|
| + break
|
| + args.append(p_test(s))
|
| + arg_tuple = ExprNodes.TupleNode(pos, args = args)
|
| + return Nodes.PrintStatNode(pos,
|
| + arg_tuple = arg_tuple, stream = stream,
|
| + append_newline = not ends_with_comma)
|
| +
|
| +def p_exec_statement(s):
|
| + # s.sy == 'exec'
|
| + pos = s.position()
|
| + s.next()
|
| + code = p_bit_expr(s)
|
| + if isinstance(code, ExprNodes.TupleNode):
|
| + # Py3 compatibility syntax
|
| + tuple_variant = True
|
| + args = code.args
|
| + if len(args) not in (2, 3):
|
| + s.error("expected tuple of length 2 or 3, got length %d" % len(args),
|
| + pos=pos, fatal=False)
|
| + args = [code]
|
| + else:
|
| + tuple_variant = False
|
| + args = [code]
|
| + if s.sy == 'in':
|
| + if tuple_variant:
|
| + s.error("tuple variant of exec does not support additional 'in' arguments",
|
| + fatal=False)
|
| + s.next()
|
| + args.append(p_test(s))
|
| + if s.sy == ',':
|
| + s.next()
|
| + args.append(p_test(s))
|
| + return Nodes.ExecStatNode(pos, args=args)
|
| +
|
| +def p_del_statement(s):
|
| + # s.sy == 'del'
|
| + pos = s.position()
|
| + s.next()
|
| + # FIXME: 'exprlist' in Python
|
| + args = p_simple_expr_list(s)
|
| + return Nodes.DelStatNode(pos, args = args)
|
| +
|
| +def p_pass_statement(s, with_newline = 0):
|
| + pos = s.position()
|
| + s.expect('pass')
|
| + if with_newline:
|
| + s.expect_newline("Expected a newline")
|
| + return Nodes.PassStatNode(pos)
|
| +
|
| +def p_break_statement(s):
|
| + # s.sy == 'break'
|
| + pos = s.position()
|
| + s.next()
|
| + return Nodes.BreakStatNode(pos)
|
| +
|
| +def p_continue_statement(s):
|
| + # s.sy == 'continue'
|
| + pos = s.position()
|
| + s.next()
|
| + return Nodes.ContinueStatNode(pos)
|
| +
|
| +def p_return_statement(s):
|
| + # s.sy == 'return'
|
| + pos = s.position()
|
| + s.next()
|
| + if s.sy not in statement_terminators:
|
| + value = p_testlist(s)
|
| + else:
|
| + value = None
|
| + return Nodes.ReturnStatNode(pos, value = value)
|
| +
|
| +def p_raise_statement(s):
|
| + # s.sy == 'raise'
|
| + pos = s.position()
|
| + s.next()
|
| + exc_type = None
|
| + exc_value = None
|
| + exc_tb = None
|
| + cause = None
|
| + if s.sy not in statement_terminators:
|
| + exc_type = p_test(s)
|
| + if s.sy == ',':
|
| + s.next()
|
| + exc_value = p_test(s)
|
| + if s.sy == ',':
|
| + s.next()
|
| + exc_tb = p_test(s)
|
| + elif s.sy == 'from':
|
| + s.next()
|
| + cause = p_test(s)
|
| + if exc_type or exc_value or exc_tb:
|
| + return Nodes.RaiseStatNode(pos,
|
| + exc_type = exc_type,
|
| + exc_value = exc_value,
|
| + exc_tb = exc_tb,
|
| + cause = cause)
|
| + else:
|
| + return Nodes.ReraiseStatNode(pos)
|
| +
|
| +def p_import_statement(s):
|
| + # s.sy in ('import', 'cimport')
|
| + pos = s.position()
|
| + kind = s.sy
|
| + s.next()
|
| + items = [p_dotted_name(s, as_allowed = 1)]
|
| + while s.sy == ',':
|
| + s.next()
|
| + items.append(p_dotted_name(s, as_allowed = 1))
|
| + stats = []
|
| + for pos, target_name, dotted_name, as_name in items:
|
| + dotted_name = EncodedString(dotted_name)
|
| + if kind == 'cimport':
|
| + stat = Nodes.CImportStatNode(pos,
|
| + module_name = dotted_name,
|
| + as_name = as_name)
|
| + else:
|
| + if as_name and "." in dotted_name:
|
| + name_list = ExprNodes.ListNode(pos, args = [
|
| + ExprNodes.IdentifierStringNode(pos, value = EncodedString("*"))])
|
| + else:
|
| + name_list = None
|
| + stat = Nodes.SingleAssignmentNode(pos,
|
| + lhs = ExprNodes.NameNode(pos,
|
| + name = as_name or target_name),
|
| + rhs = ExprNodes.ImportNode(pos,
|
| + module_name = ExprNodes.IdentifierStringNode(
|
| + pos, value = dotted_name),
|
| + level = None,
|
| + name_list = name_list))
|
| + stats.append(stat)
|
| + return Nodes.StatListNode(pos, stats = stats)
|
| +
|
| +def p_from_import_statement(s, first_statement = 0):
|
| + # s.sy == 'from'
|
| + pos = s.position()
|
| + s.next()
|
| + if s.sy == '.':
|
| + # count relative import level
|
| + level = 0
|
| + while s.sy == '.':
|
| + level += 1
|
| + s.next()
|
| + if s.sy == 'cimport':
|
| + s.error("Relative cimport is not supported yet")
|
| + else:
|
| + level = None
|
| + if level is not None and s.sy == 'import':
|
| + # we are dealing with "from .. import foo, bar"
|
| + dotted_name_pos, dotted_name = s.position(), ''
|
| + elif level is not None and s.sy == 'cimport':
|
| + # "from .. cimport"
|
| + s.error("Relative cimport is not supported yet")
|
| + else:
|
| + (dotted_name_pos, _, dotted_name, _) = \
|
| + p_dotted_name(s, as_allowed = 0)
|
| + if s.sy in ('import', 'cimport'):
|
| + kind = s.sy
|
| + s.next()
|
| + else:
|
| + s.error("Expected 'import' or 'cimport'")
|
| +
|
| + is_cimport = kind == 'cimport'
|
| + is_parenthesized = False
|
| + if s.sy == '*':
|
| + imported_names = [(s.position(), "*", None, None)]
|
| + s.next()
|
| + else:
|
| + if s.sy == '(':
|
| + is_parenthesized = True
|
| + s.next()
|
| + imported_names = [p_imported_name(s, is_cimport)]
|
| + while s.sy == ',':
|
| + s.next()
|
| + if is_parenthesized and s.sy == ')':
|
| + break
|
| + imported_names.append(p_imported_name(s, is_cimport))
|
| + if is_parenthesized:
|
| + s.expect(')')
|
| + dotted_name = EncodedString(dotted_name)
|
| + if dotted_name == '__future__':
|
| + if not first_statement:
|
| + s.error("from __future__ imports must occur at the beginning of the file")
|
| + elif level is not None:
|
| + s.error("invalid syntax")
|
| + else:
|
| + for (name_pos, name, as_name, kind) in imported_names:
|
| + if name == "braces":
|
| + s.error("not a chance", name_pos)
|
| + break
|
| + try:
|
| + directive = getattr(Future, name)
|
| + except AttributeError:
|
| + s.error("future feature %s is not defined" % name, name_pos)
|
| + break
|
| + s.context.future_directives.add(directive)
|
| + return Nodes.PassStatNode(pos)
|
| + elif kind == 'cimport':
|
| + return Nodes.FromCImportStatNode(pos,
|
| + module_name = dotted_name,
|
| + imported_names = imported_names)
|
| + else:
|
| + imported_name_strings = []
|
| + items = []
|
| + for (name_pos, name, as_name, kind) in imported_names:
|
| + encoded_name = EncodedString(name)
|
| + imported_name_strings.append(
|
| + ExprNodes.IdentifierStringNode(name_pos, value = encoded_name))
|
| + items.append(
|
| + (name,
|
| + ExprNodes.NameNode(name_pos,
|
| + name = as_name or name)))
|
| + import_list = ExprNodes.ListNode(
|
| + imported_names[0][0], args = imported_name_strings)
|
| + dotted_name = EncodedString(dotted_name)
|
| + return Nodes.FromImportStatNode(pos,
|
| + module = ExprNodes.ImportNode(dotted_name_pos,
|
| + module_name = ExprNodes.IdentifierStringNode(pos, value = dotted_name),
|
| + level = level,
|
| + name_list = import_list),
|
| + items = items)
|
| +
|
| +imported_name_kinds = cython.declare(
|
| + set, set(['class', 'struct', 'union']))
|
| +
|
| +def p_imported_name(s, is_cimport):
|
| + pos = s.position()
|
| + kind = None
|
| + if is_cimport and s.systring in imported_name_kinds:
|
| + kind = s.systring
|
| + s.next()
|
| + name = p_ident(s)
|
| + as_name = p_as_name(s)
|
| + return (pos, name, as_name, kind)
|
| +
|
| +def p_dotted_name(s, as_allowed):
|
| + pos = s.position()
|
| + target_name = p_ident(s)
|
| + as_name = None
|
| + names = [target_name]
|
| + while s.sy == '.':
|
| + s.next()
|
| + names.append(p_ident(s))
|
| + if as_allowed:
|
| + as_name = p_as_name(s)
|
| + return (pos, target_name, u'.'.join(names), as_name)
|
| +
|
| +def p_as_name(s):
|
| + if s.sy == 'IDENT' and s.systring == 'as':
|
| + s.next()
|
| + return p_ident(s)
|
| + else:
|
| + return None
|
| +
|
| +def p_assert_statement(s):
|
| + # s.sy == 'assert'
|
| + pos = s.position()
|
| + s.next()
|
| + cond = p_test(s)
|
| + if s.sy == ',':
|
| + s.next()
|
| + value = p_test(s)
|
| + else:
|
| + value = None
|
| + return Nodes.AssertStatNode(pos, cond = cond, value = value)
|
| +
|
| +statement_terminators = cython.declare(set, set([';', 'NEWLINE', 'EOF']))
|
| +
|
| +def p_if_statement(s):
|
| + # s.sy == 'if'
|
| + pos = s.position()
|
| + s.next()
|
| + if_clauses = [p_if_clause(s)]
|
| + while s.sy == 'elif':
|
| + s.next()
|
| + if_clauses.append(p_if_clause(s))
|
| + else_clause = p_else_clause(s)
|
| + return Nodes.IfStatNode(pos,
|
| + if_clauses = if_clauses, else_clause = else_clause)
|
| +
|
| +def p_if_clause(s):
|
| + pos = s.position()
|
| + test = p_test(s)
|
| + body = p_suite(s)
|
| + return Nodes.IfClauseNode(pos,
|
| + condition = test, body = body)
|
| +
|
| +def p_else_clause(s):
|
| + if s.sy == 'else':
|
| + s.next()
|
| + return p_suite(s)
|
| + else:
|
| + return None
|
| +
|
| +def p_while_statement(s):
|
| + # s.sy == 'while'
|
| + pos = s.position()
|
| + s.next()
|
| + test = p_test(s)
|
| + body = p_suite(s)
|
| + else_clause = p_else_clause(s)
|
| + return Nodes.WhileStatNode(pos,
|
| + condition = test, body = body,
|
| + else_clause = else_clause)
|
| +
|
| +def p_for_statement(s):
|
| + # s.sy == 'for'
|
| + pos = s.position()
|
| + s.next()
|
| + kw = p_for_bounds(s, allow_testlist=True)
|
| + body = p_suite(s)
|
| + else_clause = p_else_clause(s)
|
| + kw.update(body = body, else_clause = else_clause)
|
| + return Nodes.ForStatNode(pos, **kw)
|
| +
|
| +def p_for_bounds(s, allow_testlist=True):
|
| + target = p_for_target(s)
|
| + if s.sy == 'in':
|
| + s.next()
|
| + iterator = p_for_iterator(s, allow_testlist)
|
| + return dict( target = target, iterator = iterator )
|
| + elif not s.in_python_file:
|
| + if s.sy == 'from':
|
| + s.next()
|
| + bound1 = p_bit_expr(s)
|
| + else:
|
| + # Support shorter "for a <= x < b" syntax
|
| + bound1, target = target, None
|
| + rel1 = p_for_from_relation(s)
|
| + name2_pos = s.position()
|
| + name2 = p_ident(s)
|
| + rel2_pos = s.position()
|
| + rel2 = p_for_from_relation(s)
|
| + bound2 = p_bit_expr(s)
|
| + step = p_for_from_step(s)
|
| + if target is None:
|
| + target = ExprNodes.NameNode(name2_pos, name = name2)
|
| + else:
|
| + if not target.is_name:
|
| + error(target.pos,
|
| + "Target of for-from statement must be a variable name")
|
| + elif name2 != target.name:
|
| + error(name2_pos,
|
| + "Variable name in for-from range does not match target")
|
| + if rel1[0] != rel2[0]:
|
| + error(rel2_pos,
|
| + "Relation directions in for-from do not match")
|
| + return dict(target = target,
|
| + bound1 = bound1,
|
| + relation1 = rel1,
|
| + relation2 = rel2,
|
| + bound2 = bound2,
|
| + step = step,
|
| + )
|
| + else:
|
| + s.expect('in')
|
| + return {}
|
| +
|
| +def p_for_from_relation(s):
|
| + if s.sy in inequality_relations:
|
| + op = s.sy
|
| + s.next()
|
| + return op
|
| + else:
|
| + s.error("Expected one of '<', '<=', '>' '>='")
|
| +
|
| +def p_for_from_step(s):
|
| + if s.sy == 'IDENT' and s.systring == 'by':
|
| + s.next()
|
| + step = p_bit_expr(s)
|
| + return step
|
| + else:
|
| + return None
|
| +
|
| +inequality_relations = cython.declare(set, set(['<', '<=', '>', '>=']))
|
| +
|
| +def p_target(s, terminator):
|
| + pos = s.position()
|
| + expr = p_starred_expr(s)
|
| + if s.sy == ',':
|
| + s.next()
|
| + exprs = [expr]
|
| + while s.sy != terminator:
|
| + exprs.append(p_starred_expr(s))
|
| + if s.sy != ',':
|
| + break
|
| + s.next()
|
| + return ExprNodes.TupleNode(pos, args = exprs)
|
| + else:
|
| + return expr
|
| +
|
| +def p_for_target(s):
|
| + return p_target(s, 'in')
|
| +
|
| +def p_for_iterator(s, allow_testlist=True):
|
| + pos = s.position()
|
| + if allow_testlist:
|
| + expr = p_testlist(s)
|
| + else:
|
| + expr = p_or_test(s)
|
| + return ExprNodes.IteratorNode(pos, sequence = expr)
|
| +
|
| +def p_try_statement(s):
|
| + # s.sy == 'try'
|
| + pos = s.position()
|
| + s.next()
|
| + body = p_suite(s)
|
| + except_clauses = []
|
| + else_clause = None
|
| + if s.sy in ('except', 'else'):
|
| + while s.sy == 'except':
|
| + except_clauses.append(p_except_clause(s))
|
| + if s.sy == 'else':
|
| + s.next()
|
| + else_clause = p_suite(s)
|
| + body = Nodes.TryExceptStatNode(pos,
|
| + body = body, except_clauses = except_clauses,
|
| + else_clause = else_clause)
|
| + if s.sy != 'finally':
|
| + return body
|
| + # try-except-finally is equivalent to nested try-except/try-finally
|
| + if s.sy == 'finally':
|
| + s.next()
|
| + finally_clause = p_suite(s)
|
| + return Nodes.TryFinallyStatNode(pos,
|
| + body = body, finally_clause = finally_clause)
|
| + else:
|
| + s.error("Expected 'except' or 'finally'")
|
| +
|
| +def p_except_clause(s):
|
| + # s.sy == 'except'
|
| + pos = s.position()
|
| + s.next()
|
| + exc_type = None
|
| + exc_value = None
|
| + is_except_as = False
|
| + if s.sy != ':':
|
| + exc_type = p_test(s)
|
| + # normalise into list of single exception tests
|
| + if isinstance(exc_type, ExprNodes.TupleNode):
|
| + exc_type = exc_type.args
|
| + else:
|
| + exc_type = [exc_type]
|
| + if s.sy == ',' or (s.sy == 'IDENT' and s.systring == 'as'
|
| + and s.context.language_level == 2):
|
| + s.next()
|
| + exc_value = p_test(s)
|
| + elif s.sy == 'IDENT' and s.systring == 'as':
|
| + # Py3 syntax requires a name here
|
| + s.next()
|
| + pos2 = s.position()
|
| + name = p_ident(s)
|
| + exc_value = ExprNodes.NameNode(pos2, name = name)
|
| + is_except_as = True
|
| + body = p_suite(s)
|
| + return Nodes.ExceptClauseNode(pos,
|
| + pattern = exc_type, target = exc_value,
|
| + body = body, is_except_as=is_except_as)
|
| +
|
| +def p_include_statement(s, ctx):
|
| + pos = s.position()
|
| + s.next() # 'include'
|
| + unicode_include_file_name = p_string_literal(s, 'u')[2]
|
| + s.expect_newline("Syntax error in include statement")
|
| + if s.compile_time_eval:
|
| + include_file_name = unicode_include_file_name
|
| + include_file_path = s.context.find_include_file(include_file_name, pos)
|
| + if include_file_path:
|
| + s.included_files.append(include_file_name)
|
| + f = Utils.open_source_file(include_file_path, mode="rU")
|
| + source_desc = FileSourceDescriptor(include_file_path)
|
| + s2 = PyrexScanner(f, source_desc, s, source_encoding=f.encoding, parse_comments=s.parse_comments)
|
| + try:
|
| + tree = p_statement_list(s2, ctx)
|
| + finally:
|
| + f.close()
|
| + return tree
|
| + else:
|
| + return None
|
| + else:
|
| + return Nodes.PassStatNode(pos)
|
| +
|
| +def p_with_statement(s):
|
| + s.next() # 'with'
|
| + if s.systring == 'template' and not s.in_python_file:
|
| + node = p_with_template(s)
|
| + else:
|
| + node = p_with_items(s)
|
| + return node
|
| +
|
| +def p_with_items(s):
|
| + pos = s.position()
|
| + if not s.in_python_file and s.sy == 'IDENT' and s.systring in ('nogil', 'gil'):
|
| + state = s.systring
|
| + s.next()
|
| + if s.sy == ',':
|
| + s.next()
|
| + body = p_with_items(s)
|
| + else:
|
| + body = p_suite(s)
|
| + return Nodes.GILStatNode(pos, state = state, body = body)
|
| + else:
|
| + manager = p_test(s)
|
| + target = None
|
| + if s.sy == 'IDENT' and s.systring == 'as':
|
| + s.next()
|
| + target = p_starred_expr(s)
|
| + if s.sy == ',':
|
| + s.next()
|
| + body = p_with_items(s)
|
| + else:
|
| + body = p_suite(s)
|
| + return Nodes.WithStatNode(pos, manager = manager,
|
| + target = target, body = body)
|
| +
|
| +def p_with_template(s):
|
| + pos = s.position()
|
| + templates = []
|
| + s.next()
|
| + s.expect('[')
|
| + templates.append(s.systring)
|
| + s.next()
|
| + while s.systring == ',':
|
| + s.next()
|
| + templates.append(s.systring)
|
| + s.next()
|
| + s.expect(']')
|
| + if s.sy == ':':
|
| + s.next()
|
| + s.expect_newline("Syntax error in template function declaration")
|
| + s.expect_indent()
|
| + body_ctx = Ctx()
|
| + body_ctx.templates = templates
|
| + func_or_var = p_c_func_or_var_declaration(s, pos, body_ctx)
|
| + s.expect_dedent()
|
| + return func_or_var
|
| + else:
|
| + error(pos, "Syntax error in template function declaration")
|
| +
|
| +def p_simple_statement(s, first_statement = 0):
|
| + #print "p_simple_statement:", s.sy, s.systring ###
|
| + if s.sy == 'global':
|
| + node = p_global_statement(s)
|
| + elif s.sy == 'nonlocal':
|
| + node = p_nonlocal_statement(s)
|
| + elif s.sy == 'print':
|
| + node = p_print_statement(s)
|
| + elif s.sy == 'exec':
|
| + node = p_exec_statement(s)
|
| + elif s.sy == 'del':
|
| + node = p_del_statement(s)
|
| + elif s.sy == 'break':
|
| + node = p_break_statement(s)
|
| + elif s.sy == 'continue':
|
| + node = p_continue_statement(s)
|
| + elif s.sy == 'return':
|
| + node = p_return_statement(s)
|
| + elif s.sy == 'raise':
|
| + node = p_raise_statement(s)
|
| + elif s.sy in ('import', 'cimport'):
|
| + node = p_import_statement(s)
|
| + elif s.sy == 'from':
|
| + node = p_from_import_statement(s, first_statement = first_statement)
|
| + elif s.sy == 'yield':
|
| + node = p_yield_statement(s)
|
| + elif s.sy == 'assert':
|
| + node = p_assert_statement(s)
|
| + elif s.sy == 'pass':
|
| + node = p_pass_statement(s)
|
| + else:
|
| + node = p_expression_or_assignment(s)
|
| + return node
|
| +
|
| +def p_simple_statement_list(s, ctx, first_statement = 0):
|
| + # Parse a series of simple statements on one line
|
| + # separated by semicolons.
|
| + stat = p_simple_statement(s, first_statement = first_statement)
|
| + pos = stat.pos
|
| + stats = []
|
| + if not isinstance(stat, Nodes.PassStatNode):
|
| + stats.append(stat)
|
| + while s.sy == ';':
|
| + #print "p_simple_statement_list: maybe more to follow" ###
|
| + s.next()
|
| + if s.sy in ('NEWLINE', 'EOF'):
|
| + break
|
| + stat = p_simple_statement(s, first_statement = first_statement)
|
| + if isinstance(stat, Nodes.PassStatNode):
|
| + continue
|
| + stats.append(stat)
|
| + first_statement = False
|
| +
|
| + if not stats:
|
| + stat = Nodes.PassStatNode(pos)
|
| + elif len(stats) == 1:
|
| + stat = stats[0]
|
| + else:
|
| + stat = Nodes.StatListNode(pos, stats = stats)
|
| + s.expect_newline("Syntax error in simple statement list")
|
| + return stat
|
| +
|
| +def p_compile_time_expr(s):
|
| + old = s.compile_time_expr
|
| + s.compile_time_expr = 1
|
| + expr = p_testlist(s)
|
| + s.compile_time_expr = old
|
| + return expr
|
| +
|
| +def p_DEF_statement(s):
|
| + pos = s.position()
|
| + denv = s.compile_time_env
|
| + s.next() # 'DEF'
|
| + name = p_ident(s)
|
| + s.expect('=')
|
| + expr = p_compile_time_expr(s)
|
| + value = expr.compile_time_value(denv)
|
| + #print "p_DEF_statement: %s = %r" % (name, value) ###
|
| + denv.declare(name, value)
|
| + s.expect_newline()
|
| + return Nodes.PassStatNode(pos)
|
| +
|
| +def p_IF_statement(s, ctx):
|
| + pos = s.position()
|
| + saved_eval = s.compile_time_eval
|
| + current_eval = saved_eval
|
| + denv = s.compile_time_env
|
| + result = None
|
| + while 1:
|
| + s.next() # 'IF' or 'ELIF'
|
| + expr = p_compile_time_expr(s)
|
| + s.compile_time_eval = current_eval and bool(expr.compile_time_value(denv))
|
| + body = p_suite(s, ctx)
|
| + if s.compile_time_eval:
|
| + result = body
|
| + current_eval = 0
|
| + if s.sy != 'ELIF':
|
| + break
|
| + if s.sy == 'ELSE':
|
| + s.next()
|
| + s.compile_time_eval = current_eval
|
| + body = p_suite(s, ctx)
|
| + if current_eval:
|
| + result = body
|
| + if not result:
|
| + result = Nodes.PassStatNode(pos)
|
| + s.compile_time_eval = saved_eval
|
| + return result
|
| +
|
| +def p_statement(s, ctx, first_statement = 0):
|
| + cdef_flag = ctx.cdef_flag
|
| + decorators = None
|
| + if s.sy == 'ctypedef':
|
| + if ctx.level not in ('module', 'module_pxd'):
|
| + s.error("ctypedef statement not allowed here")
|
| + #if ctx.api:
|
| + # error(s.position(), "'api' not allowed with 'ctypedef'")
|
| + return p_ctypedef_statement(s, ctx)
|
| + elif s.sy == 'DEF':
|
| + return p_DEF_statement(s)
|
| + elif s.sy == 'IF':
|
| + return p_IF_statement(s, ctx)
|
| + elif s.sy == 'DECORATOR':
|
| + if ctx.level not in ('module', 'class', 'c_class', 'function', 'property', 'module_pxd', 'c_class_pxd', 'other'):
|
| + s.error('decorator not allowed here')
|
| + s.level = ctx.level
|
| + decorators = p_decorators(s)
|
| + bad_toks = 'def', 'cdef', 'cpdef', 'class'
|
| + if not ctx.allow_struct_enum_decorator and s.sy not in bad_toks:
|
| + s.error("Decorators can only be followed by functions or classes")
|
| + elif s.sy == 'pass' and cdef_flag:
|
| + # empty cdef block
|
| + return p_pass_statement(s, with_newline = 1)
|
| +
|
| + overridable = 0
|
| + if s.sy == 'cdef':
|
| + cdef_flag = 1
|
| + s.next()
|
| + elif s.sy == 'cpdef':
|
| + cdef_flag = 1
|
| + overridable = 1
|
| + s.next()
|
| + if cdef_flag:
|
| + if ctx.level not in ('module', 'module_pxd', 'function', 'c_class', 'c_class_pxd'):
|
| + s.error('cdef statement not allowed here')
|
| + s.level = ctx.level
|
| + node = p_cdef_statement(s, ctx(overridable = overridable))
|
| + if decorators is not None:
|
| + tup = Nodes.CFuncDefNode, Nodes.CVarDefNode, Nodes.CClassDefNode
|
| + if ctx.allow_struct_enum_decorator:
|
| + tup += Nodes.CStructOrUnionDefNode, Nodes.CEnumDefNode
|
| + if not isinstance(node, tup):
|
| + s.error("Decorators can only be followed by functions or classes")
|
| + node.decorators = decorators
|
| + return node
|
| + else:
|
| + if ctx.api:
|
| + s.error("'api' not allowed with this statement", fatal=False)
|
| + elif s.sy == 'def':
|
| + # def statements aren't allowed in pxd files, except
|
| + # as part of a cdef class
|
| + if ('pxd' in ctx.level) and (ctx.level != 'c_class_pxd'):
|
| + s.error('def statement not allowed here')
|
| + s.level = ctx.level
|
| + return p_def_statement(s, decorators)
|
| + elif s.sy == 'class':
|
| + if ctx.level not in ('module', 'function', 'class', 'other'):
|
| + s.error("class definition not allowed here")
|
| + return p_class_statement(s, decorators)
|
| + elif s.sy == 'include':
|
| + if ctx.level not in ('module', 'module_pxd'):
|
| + s.error("include statement not allowed here")
|
| + return p_include_statement(s, ctx)
|
| + elif ctx.level == 'c_class' and s.sy == 'IDENT' and s.systring == 'property':
|
| + return p_property_decl(s)
|
| + elif s.sy == 'pass' and ctx.level != 'property':
|
| + return p_pass_statement(s, with_newline=True)
|
| + else:
|
| + if ctx.level in ('c_class_pxd', 'property'):
|
| + node = p_ignorable_statement(s)
|
| + if node is not None:
|
| + return node
|
| + s.error("Executable statement not allowed here")
|
| + if s.sy == 'if':
|
| + return p_if_statement(s)
|
| + elif s.sy == 'while':
|
| + return p_while_statement(s)
|
| + elif s.sy == 'for':
|
| + return p_for_statement(s)
|
| + elif s.sy == 'try':
|
| + return p_try_statement(s)
|
| + elif s.sy == 'with':
|
| + return p_with_statement(s)
|
| + else:
|
| + return p_simple_statement_list(
|
| + s, ctx, first_statement = first_statement)
|
| +
|
| +def p_statement_list(s, ctx, first_statement = 0):
|
| + # Parse a series of statements separated by newlines.
|
| + pos = s.position()
|
| + stats = []
|
| + while s.sy not in ('DEDENT', 'EOF'):
|
| + stat = p_statement(s, ctx, first_statement = first_statement)
|
| + if isinstance(stat, Nodes.PassStatNode):
|
| + continue
|
| + stats.append(stat)
|
| + first_statement = False
|
| + if not stats:
|
| + return Nodes.PassStatNode(pos)
|
| + elif len(stats) == 1:
|
| + return stats[0]
|
| + else:
|
| + return Nodes.StatListNode(pos, stats = stats)
|
| +
|
| +
|
| +def p_suite(s, ctx=Ctx()):
|
| + return p_suite_with_docstring(s, ctx, with_doc_only=False)[1]
|
| +
|
| +
|
| +def p_suite_with_docstring(s, ctx, with_doc_only=False):
|
| + s.expect(':')
|
| + doc = None
|
| + if s.sy == 'NEWLINE':
|
| + s.next()
|
| + s.expect_indent()
|
| + if with_doc_only:
|
| + doc = p_doc_string(s)
|
| + body = p_statement_list(s, ctx)
|
| + s.expect_dedent()
|
| + else:
|
| + if ctx.api:
|
| + s.error("'api' not allowed with this statement", fatal=False)
|
| + if ctx.level in ('module', 'class', 'function', 'other'):
|
| + body = p_simple_statement_list(s, ctx)
|
| + else:
|
| + body = p_pass_statement(s)
|
| + s.expect_newline("Syntax error in declarations")
|
| + if not with_doc_only:
|
| + doc, body = _extract_docstring(body)
|
| + return doc, body
|
| +
|
| +
|
| +def p_positional_and_keyword_args(s, end_sy_set, templates = None):
|
| + """
|
| + Parses positional and keyword arguments. end_sy_set
|
| + should contain any s.sy that terminate the argument list.
|
| + Argument expansion (* and **) are not allowed.
|
| +
|
| + Returns: (positional_args, keyword_args)
|
| + """
|
| + positional_args = []
|
| + keyword_args = []
|
| + pos_idx = 0
|
| +
|
| + while s.sy not in end_sy_set:
|
| + if s.sy == '*' or s.sy == '**':
|
| + s.error('Argument expansion not allowed here.', fatal=False)
|
| +
|
| + parsed_type = False
|
| + if s.sy == 'IDENT' and s.peek()[0] == '=':
|
| + ident = s.systring
|
| + s.next() # s.sy is '='
|
| + s.next()
|
| + if looking_at_expr(s):
|
| + arg = p_test(s)
|
| + else:
|
| + base_type = p_c_base_type(s, templates = templates)
|
| + declarator = p_c_declarator(s, empty = 1)
|
| + arg = Nodes.CComplexBaseTypeNode(base_type.pos,
|
| + base_type = base_type, declarator = declarator)
|
| + parsed_type = True
|
| + keyword_node = ExprNodes.IdentifierStringNode(
|
| + arg.pos, value = EncodedString(ident))
|
| + keyword_args.append((keyword_node, arg))
|
| + was_keyword = True
|
| +
|
| + else:
|
| + if looking_at_expr(s):
|
| + arg = p_test(s)
|
| + else:
|
| + base_type = p_c_base_type(s, templates = templates)
|
| + declarator = p_c_declarator(s, empty = 1)
|
| + arg = Nodes.CComplexBaseTypeNode(base_type.pos,
|
| + base_type = base_type, declarator = declarator)
|
| + parsed_type = True
|
| + positional_args.append(arg)
|
| + pos_idx += 1
|
| + if len(keyword_args) > 0:
|
| + s.error("Non-keyword arg following keyword arg",
|
| + pos=arg.pos)
|
| +
|
| + if s.sy != ',':
|
| + if s.sy not in end_sy_set:
|
| + if parsed_type:
|
| + s.error("Unmatched %s" % " or ".join(end_sy_set))
|
| + break
|
| + s.next()
|
| + return positional_args, keyword_args
|
| +
|
| +def p_c_base_type(s, self_flag = 0, nonempty = 0, templates = None):
|
| + # If self_flag is true, this is the base type for the
|
| + # self argument of a C method of an extension type.
|
| + if s.sy == '(':
|
| + return p_c_complex_base_type(s, templates = templates)
|
| + else:
|
| + return p_c_simple_base_type(s, self_flag, nonempty = nonempty, templates = templates)
|
| +
|
| +def p_calling_convention(s):
|
| + if s.sy == 'IDENT' and s.systring in calling_convention_words:
|
| + result = s.systring
|
| + s.next()
|
| + return result
|
| + else:
|
| + return ""
|
| +
|
| +calling_convention_words = cython.declare(
|
| + set, set(["__stdcall", "__cdecl", "__fastcall"]))
|
| +
|
| +def p_c_complex_base_type(s, templates = None):
|
| + # s.sy == '('
|
| + pos = s.position()
|
| + s.next()
|
| + base_type = p_c_base_type(s, templates = templates)
|
| + declarator = p_c_declarator(s, empty = 1)
|
| + s.expect(')')
|
| + type_node = Nodes.CComplexBaseTypeNode(pos,
|
| + base_type = base_type, declarator = declarator)
|
| + if s.sy == '[':
|
| + if is_memoryviewslice_access(s):
|
| + type_node = p_memoryviewslice_access(s, type_node)
|
| + else:
|
| + type_node = p_buffer_or_template(s, type_node, templates)
|
| + return type_node
|
| +
|
| +
|
| +def p_c_simple_base_type(s, self_flag, nonempty, templates = None):
|
| + #print "p_c_simple_base_type: self_flag =", self_flag, nonempty
|
| + is_basic = 0
|
| + signed = 1
|
| + longness = 0
|
| + complex = 0
|
| + module_path = []
|
| + pos = s.position()
|
| + if not s.sy == 'IDENT':
|
| + error(pos, "Expected an identifier, found '%s'" % s.sy)
|
| + if s.systring == 'const':
|
| + s.next()
|
| + base_type = p_c_base_type(s,
|
| + self_flag = self_flag, nonempty = nonempty, templates = templates)
|
| + return Nodes.CConstTypeNode(pos, base_type = base_type)
|
| + if looking_at_base_type(s):
|
| + #print "p_c_simple_base_type: looking_at_base_type at", s.position()
|
| + is_basic = 1
|
| + if s.sy == 'IDENT' and s.systring in special_basic_c_types:
|
| + signed, longness = special_basic_c_types[s.systring]
|
| + name = s.systring
|
| + s.next()
|
| + else:
|
| + signed, longness = p_sign_and_longness(s)
|
| + if s.sy == 'IDENT' and s.systring in basic_c_type_names:
|
| + name = s.systring
|
| + s.next()
|
| + else:
|
| + name = 'int' # long [int], short [int], long [int] complex, etc.
|
| + if s.sy == 'IDENT' and s.systring == 'complex':
|
| + complex = 1
|
| + s.next()
|
| + elif looking_at_dotted_name(s):
|
| + #print "p_c_simple_base_type: looking_at_type_name at", s.position()
|
| + name = s.systring
|
| + s.next()
|
| + while s.sy == '.':
|
| + module_path.append(name)
|
| + s.next()
|
| + name = p_ident(s)
|
| + else:
|
| + name = s.systring
|
| + s.next()
|
| + if nonempty and s.sy != 'IDENT':
|
| + # Make sure this is not a declaration of a variable or function.
|
| + if s.sy == '(':
|
| + s.next()
|
| + if (s.sy == '*' or s.sy == '**' or s.sy == '&'
|
| + or (s.sy == 'IDENT' and s.systring in calling_convention_words)):
|
| + s.put_back('(', '(')
|
| + else:
|
| + s.put_back('(', '(')
|
| + s.put_back('IDENT', name)
|
| + name = None
|
| + elif s.sy not in ('*', '**', '[', '&'):
|
| + s.put_back('IDENT', name)
|
| + name = None
|
| +
|
| + type_node = Nodes.CSimpleBaseTypeNode(pos,
|
| + name = name, module_path = module_path,
|
| + is_basic_c_type = is_basic, signed = signed,
|
| + complex = complex, longness = longness,
|
| + is_self_arg = self_flag, templates = templates)
|
| +
|
| + # declarations here.
|
| + if s.sy == '[':
|
| + if is_memoryviewslice_access(s):
|
| + type_node = p_memoryviewslice_access(s, type_node)
|
| + else:
|
| + type_node = p_buffer_or_template(s, type_node, templates)
|
| +
|
| + if s.sy == '.':
|
| + s.next()
|
| + name = p_ident(s)
|
| + type_node = Nodes.CNestedBaseTypeNode(pos, base_type = type_node, name = name)
|
| +
|
| + return type_node
|
| +
|
| +def p_buffer_or_template(s, base_type_node, templates):
|
| + # s.sy == '['
|
| + pos = s.position()
|
| + s.next()
|
| + # Note that buffer_positional_options_count=1, so the only positional argument is dtype.
|
| + # For templated types, all parameters are types.
|
| + positional_args, keyword_args = (
|
| + p_positional_and_keyword_args(s, (']',), templates)
|
| + )
|
| + s.expect(']')
|
| +
|
| + if s.sy == '[':
|
| + base_type_node = p_buffer_or_template(s, base_type_node, templates)
|
| +
|
| + keyword_dict = ExprNodes.DictNode(pos,
|
| + key_value_pairs = [
|
| + ExprNodes.DictItemNode(pos=key.pos, key=key, value=value)
|
| + for key, value in keyword_args
|
| + ])
|
| + result = Nodes.TemplatedTypeNode(pos,
|
| + positional_args = positional_args,
|
| + keyword_args = keyword_dict,
|
| + base_type_node = base_type_node)
|
| + return result
|
| +
|
| +def p_bracketed_base_type(s, base_type_node, nonempty, empty):
|
| + # s.sy == '['
|
| + if empty and not nonempty:
|
| + # sizeof-like thing. Only anonymous C arrays allowed (int[SIZE]).
|
| + return base_type_node
|
| + elif not empty and nonempty:
|
| + # declaration of either memoryview slice or buffer.
|
| + if is_memoryviewslice_access(s):
|
| + return p_memoryviewslice_access(s, base_type_node)
|
| + else:
|
| + return p_buffer_or_template(s, base_type_node, None)
|
| + # return p_buffer_access(s, base_type_node)
|
| + elif not empty and not nonempty:
|
| + # only anonymous C arrays and memoryview slice arrays here. We
|
| + # disallow buffer declarations for now, due to ambiguity with anonymous
|
| + # C arrays.
|
| + if is_memoryviewslice_access(s):
|
| + return p_memoryviewslice_access(s, base_type_node)
|
| + else:
|
| + return base_type_node
|
| +
|
| +def is_memoryviewslice_access(s):
|
| + # s.sy == '['
|
| + # a memoryview slice declaration is distinguishable from a buffer access
|
| + # declaration by the first entry in the bracketed list. The buffer will
|
| + # not have an unnested colon in the first entry; the memoryview slice will.
|
| + saved = [(s.sy, s.systring)]
|
| + s.next()
|
| + retval = False
|
| + if s.systring == ':':
|
| + retval = True
|
| + elif s.sy == 'INT':
|
| + saved.append((s.sy, s.systring))
|
| + s.next()
|
| + if s.sy == ':':
|
| + retval = True
|
| +
|
| + for sv in saved[::-1]:
|
| + s.put_back(*sv)
|
| +
|
| + return retval
|
| +
|
| +def p_memoryviewslice_access(s, base_type_node):
|
| + # s.sy == '['
|
| + pos = s.position()
|
| + s.next()
|
| + subscripts, _ = p_subscript_list(s)
|
| + # make sure each entry in subscripts is a slice
|
| + for subscript in subscripts:
|
| + if len(subscript) < 2:
|
| + s.error("An axis specification in memoryview declaration does not have a ':'.")
|
| + s.expect(']')
|
| + indexes = make_slice_nodes(pos, subscripts)
|
| + result = Nodes.MemoryViewSliceTypeNode(pos,
|
| + base_type_node = base_type_node,
|
| + axes = indexes)
|
| + return result
|
| +
|
| +def looking_at_name(s):
|
| + return s.sy == 'IDENT' and not s.systring in calling_convention_words
|
| +
|
| +def looking_at_expr(s):
|
| + if s.systring in base_type_start_words:
|
| + return False
|
| + elif s.sy == 'IDENT':
|
| + is_type = False
|
| + name = s.systring
|
| + dotted_path = []
|
| + s.next()
|
| +
|
| + while s.sy == '.':
|
| + s.next()
|
| + dotted_path.append(s.systring)
|
| + s.expect('IDENT')
|
| +
|
| + saved = s.sy, s.systring
|
| + if s.sy == 'IDENT':
|
| + is_type = True
|
| + elif s.sy == '*' or s.sy == '**':
|
| + s.next()
|
| + is_type = s.sy in (')', ']')
|
| + s.put_back(*saved)
|
| + elif s.sy == '(':
|
| + s.next()
|
| + is_type = s.sy == '*'
|
| + s.put_back(*saved)
|
| + elif s.sy == '[':
|
| + s.next()
|
| + is_type = s.sy == ']'
|
| + s.put_back(*saved)
|
| +
|
| + dotted_path.reverse()
|
| + for p in dotted_path:
|
| + s.put_back('IDENT', p)
|
| + s.put_back('.', '.')
|
| +
|
| + s.put_back('IDENT', name)
|
| + return not is_type and saved[0]
|
| + else:
|
| + return True
|
| +
|
| +def looking_at_base_type(s):
|
| + #print "looking_at_base_type?", s.sy, s.systring, s.position()
|
| + return s.sy == 'IDENT' and s.systring in base_type_start_words
|
| +
|
| +def looking_at_dotted_name(s):
|
| + if s.sy == 'IDENT':
|
| + name = s.systring
|
| + s.next()
|
| + result = s.sy == '.'
|
| + s.put_back('IDENT', name)
|
| + return result
|
| + else:
|
| + return 0
|
| +
|
| +def looking_at_call(s):
|
| + "See if we're looking at a.b.c("
|
| + # Don't mess up the original position, so save and restore it.
|
| + # Unfortunately there's no good way to handle this, as a subsequent call
|
| + # to next() will not advance the position until it reads a new token.
|
| + position = s.start_line, s.start_col
|
| + result = looking_at_expr(s) == u'('
|
| + if not result:
|
| + s.start_line, s.start_col = position
|
| + return result
|
| +
|
| +basic_c_type_names = cython.declare(
|
| + set, set(["void", "char", "int", "float", "double", "bint"]))
|
| +
|
| +special_basic_c_types = cython.declare(dict, {
|
| + # name : (signed, longness)
|
| + "Py_UNICODE" : (0, 0),
|
| + "Py_UCS4" : (0, 0),
|
| + "Py_ssize_t" : (2, 0),
|
| + "ssize_t" : (2, 0),
|
| + "size_t" : (0, 0),
|
| + "ptrdiff_t" : (2, 0),
|
| +})
|
| +
|
| +sign_and_longness_words = cython.declare(
|
| + set, set(["short", "long", "signed", "unsigned"]))
|
| +
|
| +base_type_start_words = cython.declare(
|
| + set,
|
| + basic_c_type_names
|
| + | sign_and_longness_words
|
| + | set(special_basic_c_types))
|
| +
|
| +struct_enum_union = cython.declare(
|
| + set, set(["struct", "union", "enum", "packed"]))
|
| +
|
| +def p_sign_and_longness(s):
|
| + signed = 1
|
| + longness = 0
|
| + while s.sy == 'IDENT' and s.systring in sign_and_longness_words:
|
| + if s.systring == 'unsigned':
|
| + signed = 0
|
| + elif s.systring == 'signed':
|
| + signed = 2
|
| + elif s.systring == 'short':
|
| + longness = -1
|
| + elif s.systring == 'long':
|
| + longness += 1
|
| + s.next()
|
| + return signed, longness
|
| +
|
| +def p_opt_cname(s):
|
| + literal = p_opt_string_literal(s, 'u')
|
| + if literal is not None:
|
| + cname = EncodedString(literal)
|
| + cname.encoding = s.source_encoding
|
| + else:
|
| + cname = None
|
| + return cname
|
| +
|
| +def p_c_declarator(s, ctx = Ctx(), empty = 0, is_type = 0, cmethod_flag = 0,
|
| + assignable = 0, nonempty = 0,
|
| + calling_convention_allowed = 0):
|
| + # If empty is true, the declarator must be empty. If nonempty is true,
|
| + # the declarator must be nonempty. Otherwise we don't care.
|
| + # If cmethod_flag is true, then if this declarator declares
|
| + # a function, it's a C method of an extension type.
|
| + pos = s.position()
|
| + if s.sy == '(':
|
| + s.next()
|
| + if s.sy == ')' or looking_at_name(s):
|
| + base = Nodes.CNameDeclaratorNode(pos, name = EncodedString(u""), cname = None)
|
| + result = p_c_func_declarator(s, pos, ctx, base, cmethod_flag)
|
| + else:
|
| + result = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
|
| + cmethod_flag = cmethod_flag,
|
| + nonempty = nonempty,
|
| + calling_convention_allowed = 1)
|
| + s.expect(')')
|
| + else:
|
| + result = p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
|
| + assignable, nonempty)
|
| + if not calling_convention_allowed and result.calling_convention and s.sy != '(':
|
| + error(s.position(), "%s on something that is not a function"
|
| + % result.calling_convention)
|
| + while s.sy in ('[', '('):
|
| + pos = s.position()
|
| + if s.sy == '[':
|
| + result = p_c_array_declarator(s, result)
|
| + else: # sy == '('
|
| + s.next()
|
| + result = p_c_func_declarator(s, pos, ctx, result, cmethod_flag)
|
| + cmethod_flag = 0
|
| + return result
|
| +
|
| +def p_c_array_declarator(s, base):
|
| + pos = s.position()
|
| + s.next() # '['
|
| + if s.sy != ']':
|
| + dim = p_testlist(s)
|
| + else:
|
| + dim = None
|
| + s.expect(']')
|
| + return Nodes.CArrayDeclaratorNode(pos, base = base, dimension = dim)
|
| +
|
| +def p_c_func_declarator(s, pos, ctx, base, cmethod_flag):
|
| + # Opening paren has already been skipped
|
| + args = p_c_arg_list(s, ctx, cmethod_flag = cmethod_flag,
|
| + nonempty_declarators = 0)
|
| + ellipsis = p_optional_ellipsis(s)
|
| + s.expect(')')
|
| + nogil = p_nogil(s)
|
| + exc_val, exc_check = p_exception_value_clause(s)
|
| + with_gil = p_with_gil(s)
|
| + return Nodes.CFuncDeclaratorNode(pos,
|
| + base = base, args = args, has_varargs = ellipsis,
|
| + exception_value = exc_val, exception_check = exc_check,
|
| + nogil = nogil or ctx.nogil or with_gil, with_gil = with_gil)
|
| +
|
| +supported_overloaded_operators = cython.declare(set, set([
|
| + '+', '-', '*', '/', '%',
|
| + '++', '--', '~', '|', '&', '^', '<<', '>>', ',',
|
| + '==', '!=', '>=', '>', '<=', '<',
|
| + '[]', '()', '!',
|
| +]))
|
| +
|
| +def p_c_simple_declarator(s, ctx, empty, is_type, cmethod_flag,
|
| + assignable, nonempty):
|
| + pos = s.position()
|
| + calling_convention = p_calling_convention(s)
|
| + if s.sy == '*':
|
| + s.next()
|
| + if s.systring == 'const':
|
| + const_pos = s.position()
|
| + s.next()
|
| + const_base = p_c_declarator(s, ctx, empty = empty,
|
| + is_type = is_type,
|
| + cmethod_flag = cmethod_flag,
|
| + assignable = assignable,
|
| + nonempty = nonempty)
|
| + base = Nodes.CConstDeclaratorNode(const_pos, base = const_base)
|
| + else:
|
| + base = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
|
| + cmethod_flag = cmethod_flag,
|
| + assignable = assignable, nonempty = nonempty)
|
| + result = Nodes.CPtrDeclaratorNode(pos,
|
| + base = base)
|
| + elif s.sy == '**': # scanner returns this as a single token
|
| + s.next()
|
| + base = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
|
| + cmethod_flag = cmethod_flag,
|
| + assignable = assignable, nonempty = nonempty)
|
| + result = Nodes.CPtrDeclaratorNode(pos,
|
| + base = Nodes.CPtrDeclaratorNode(pos,
|
| + base = base))
|
| + elif s.sy == '&':
|
| + s.next()
|
| + base = p_c_declarator(s, ctx, empty = empty, is_type = is_type,
|
| + cmethod_flag = cmethod_flag,
|
| + assignable = assignable, nonempty = nonempty)
|
| + result = Nodes.CReferenceDeclaratorNode(pos, base = base)
|
| + else:
|
| + rhs = None
|
| + if s.sy == 'IDENT':
|
| + name = EncodedString(s.systring)
|
| + if empty:
|
| + error(s.position(), "Declarator should be empty")
|
| + s.next()
|
| + cname = p_opt_cname(s)
|
| + if name != 'operator' and s.sy == '=' and assignable:
|
| + s.next()
|
| + rhs = p_test(s)
|
| + else:
|
| + if nonempty:
|
| + error(s.position(), "Empty declarator")
|
| + name = ""
|
| + cname = None
|
| + if cname is None and ctx.namespace is not None and nonempty:
|
| + cname = ctx.namespace + "::" + name
|
| + if name == 'operator' and ctx.visibility == 'extern' and nonempty:
|
| + op = s.sy
|
| + if [1 for c in op if c in '+-*/<=>!%&|([^~,']:
|
| + s.next()
|
| + # Handle diphthong operators.
|
| + if op == '(':
|
| + s.expect(')')
|
| + op = '()'
|
| + elif op == '[':
|
| + s.expect(']')
|
| + op = '[]'
|
| + elif op in ('-', '+', '|', '&') and s.sy == op:
|
| + op *= 2 # ++, --, ...
|
| + s.next()
|
| + elif s.sy == '=':
|
| + op += s.sy # +=, -=, ...
|
| + s.next()
|
| + if op not in supported_overloaded_operators:
|
| + s.error("Overloading operator '%s' not yet supported." % op,
|
| + fatal=False)
|
| + name += op
|
| + result = Nodes.CNameDeclaratorNode(pos,
|
| + name = name, cname = cname, default = rhs)
|
| + result.calling_convention = calling_convention
|
| + return result
|
| +
|
| +def p_nogil(s):
|
| + if s.sy == 'IDENT' and s.systring == 'nogil':
|
| + s.next()
|
| + return 1
|
| + else:
|
| + return 0
|
| +
|
| +def p_with_gil(s):
|
| + if s.sy == 'with':
|
| + s.next()
|
| + s.expect_keyword('gil')
|
| + return 1
|
| + else:
|
| + return 0
|
| +
|
| +def p_exception_value_clause(s):
|
| + exc_val = None
|
| + exc_check = 0
|
| + if s.sy == 'except':
|
| + s.next()
|
| + if s.sy == '*':
|
| + exc_check = 1
|
| + s.next()
|
| + elif s.sy == '+':
|
| + exc_check = '+'
|
| + s.next()
|
| + if s.sy == 'IDENT':
|
| + name = s.systring
|
| + s.next()
|
| + exc_val = p_name(s, name)
|
| + else:
|
| + if s.sy == '?':
|
| + exc_check = 1
|
| + s.next()
|
| + exc_val = p_test(s)
|
| + return exc_val, exc_check
|
| +
|
| +c_arg_list_terminators = cython.declare(set, set(['*', '**', '.', ')']))
|
| +
|
| +def p_c_arg_list(s, ctx = Ctx(), in_pyfunc = 0, cmethod_flag = 0,
|
| + nonempty_declarators = 0, kw_only = 0, annotated = 1):
|
| + # Comma-separated list of C argument declarations, possibly empty.
|
| + # May have a trailing comma.
|
| + args = []
|
| + is_self_arg = cmethod_flag
|
| + while s.sy not in c_arg_list_terminators:
|
| + args.append(p_c_arg_decl(s, ctx, in_pyfunc, is_self_arg,
|
| + nonempty = nonempty_declarators, kw_only = kw_only,
|
| + annotated = annotated))
|
| + if s.sy != ',':
|
| + break
|
| + s.next()
|
| + is_self_arg = 0
|
| + return args
|
| +
|
| +def p_optional_ellipsis(s):
|
| + if s.sy == '.':
|
| + expect_ellipsis(s)
|
| + return 1
|
| + else:
|
| + return 0
|
| +
|
| +def p_c_arg_decl(s, ctx, in_pyfunc, cmethod_flag = 0, nonempty = 0,
|
| + kw_only = 0, annotated = 1):
|
| + pos = s.position()
|
| + not_none = or_none = 0
|
| + default = None
|
| + annotation = None
|
| + if s.in_python_file:
|
| + # empty type declaration
|
| + base_type = Nodes.CSimpleBaseTypeNode(pos,
|
| + name = None, module_path = [],
|
| + is_basic_c_type = 0, signed = 0,
|
| + complex = 0, longness = 0,
|
| + is_self_arg = cmethod_flag, templates = None)
|
| + else:
|
| + base_type = p_c_base_type(s, cmethod_flag, nonempty = nonempty)
|
| + declarator = p_c_declarator(s, ctx, nonempty = nonempty)
|
| + if s.sy in ('not', 'or') and not s.in_python_file:
|
| + kind = s.sy
|
| + s.next()
|
| + if s.sy == 'IDENT' and s.systring == 'None':
|
| + s.next()
|
| + else:
|
| + s.error("Expected 'None'")
|
| + if not in_pyfunc:
|
| + error(pos, "'%s None' only allowed in Python functions" % kind)
|
| + or_none = kind == 'or'
|
| + not_none = kind == 'not'
|
| + if annotated and s.sy == ':':
|
| + s.next()
|
| + annotation = p_test(s)
|
| + if s.sy == '=':
|
| + s.next()
|
| + if 'pxd' in ctx.level:
|
| + if s.sy not in ['*', '?']:
|
| + error(pos, "default values cannot be specified in pxd files, use ? or *")
|
| + default = ExprNodes.BoolNode(1)
|
| + s.next()
|
| + else:
|
| + default = p_test(s)
|
| + return Nodes.CArgDeclNode(pos,
|
| + base_type = base_type,
|
| + declarator = declarator,
|
| + not_none = not_none,
|
| + or_none = or_none,
|
| + default = default,
|
| + annotation = annotation,
|
| + kw_only = kw_only)
|
| +
|
| +def p_api(s):
|
| + if s.sy == 'IDENT' and s.systring == 'api':
|
| + s.next()
|
| + return 1
|
| + else:
|
| + return 0
|
| +
|
| +def p_cdef_statement(s, ctx):
|
| + pos = s.position()
|
| + ctx.visibility = p_visibility(s, ctx.visibility)
|
| + ctx.api = ctx.api or p_api(s)
|
| + if ctx.api:
|
| + if ctx.visibility not in ('private', 'public'):
|
| + error(pos, "Cannot combine 'api' with '%s'" % ctx.visibility)
|
| + if (ctx.visibility == 'extern') and s.sy == 'from':
|
| + return p_cdef_extern_block(s, pos, ctx)
|
| + elif s.sy == 'import':
|
| + s.next()
|
| + return p_cdef_extern_block(s, pos, ctx)
|
| + elif p_nogil(s):
|
| + ctx.nogil = 1
|
| + if ctx.overridable:
|
| + error(pos, "cdef blocks cannot be declared cpdef")
|
| + return p_cdef_block(s, ctx)
|
| + elif s.sy == ':':
|
| + if ctx.overridable:
|
| + error(pos, "cdef blocks cannot be declared cpdef")
|
| + return p_cdef_block(s, ctx)
|
| + elif s.sy == 'class':
|
| + if ctx.level not in ('module', 'module_pxd'):
|
| + error(pos, "Extension type definition not allowed here")
|
| + if ctx.overridable:
|
| + error(pos, "Extension types cannot be declared cpdef")
|
| + return p_c_class_definition(s, pos, ctx)
|
| + elif s.sy == 'IDENT' and s.systring == 'cppclass':
|
| + return p_cpp_class_definition(s, pos, ctx)
|
| + elif s.sy == 'IDENT' and s.systring in struct_enum_union:
|
| + if ctx.level not in ('module', 'module_pxd'):
|
| + error(pos, "C struct/union/enum definition not allowed here")
|
| + if ctx.overridable:
|
| + error(pos, "C struct/union/enum cannot be declared cpdef")
|
| + return p_struct_enum(s, pos, ctx)
|
| + elif s.sy == 'IDENT' and s.systring == 'fused':
|
| + return p_fused_definition(s, pos, ctx)
|
| + else:
|
| + return p_c_func_or_var_declaration(s, pos, ctx)
|
| +
|
| +def p_cdef_block(s, ctx):
|
| + return p_suite(s, ctx(cdef_flag = 1))
|
| +
|
| +def p_cdef_extern_block(s, pos, ctx):
|
| + if ctx.overridable:
|
| + error(pos, "cdef extern blocks cannot be declared cpdef")
|
| + include_file = None
|
| + s.expect('from')
|
| + if s.sy == '*':
|
| + s.next()
|
| + else:
|
| + include_file = p_string_literal(s, 'u')[2]
|
| + ctx = ctx(cdef_flag = 1, visibility = 'extern')
|
| + if s.systring == "namespace":
|
| + s.next()
|
| + ctx.namespace = p_string_literal(s, 'u')[2]
|
| + if p_nogil(s):
|
| + ctx.nogil = 1
|
| + body = p_suite(s, ctx)
|
| + return Nodes.CDefExternNode(pos,
|
| + include_file = include_file,
|
| + body = body,
|
| + namespace = ctx.namespace)
|
| +
|
| +def p_c_enum_definition(s, pos, ctx):
|
| + # s.sy == ident 'enum'
|
| + s.next()
|
| + if s.sy == 'IDENT':
|
| + name = s.systring
|
| + s.next()
|
| + cname = p_opt_cname(s)
|
| + if cname is None and ctx.namespace is not None:
|
| + cname = ctx.namespace + "::" + name
|
| + else:
|
| + name = None
|
| + cname = None
|
| + items = None
|
| + s.expect(':')
|
| + items = []
|
| + if s.sy != 'NEWLINE':
|
| + p_c_enum_line(s, ctx, items)
|
| + else:
|
| + s.next() # 'NEWLINE'
|
| + s.expect_indent()
|
| + while s.sy not in ('DEDENT', 'EOF'):
|
| + p_c_enum_line(s, ctx, items)
|
| + s.expect_dedent()
|
| + return Nodes.CEnumDefNode(
|
| + pos, name = name, cname = cname, items = items,
|
| + typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
|
| + api = ctx.api, in_pxd = ctx.level == 'module_pxd')
|
| +
|
| +def p_c_enum_line(s, ctx, items):
|
| + if s.sy != 'pass':
|
| + p_c_enum_item(s, ctx, items)
|
| + while s.sy == ',':
|
| + s.next()
|
| + if s.sy in ('NEWLINE', 'EOF'):
|
| + break
|
| + p_c_enum_item(s, ctx, items)
|
| + else:
|
| + s.next()
|
| + s.expect_newline("Syntax error in enum item list")
|
| +
|
| +def p_c_enum_item(s, ctx, items):
|
| + pos = s.position()
|
| + name = p_ident(s)
|
| + cname = p_opt_cname(s)
|
| + if cname is None and ctx.namespace is not None:
|
| + cname = ctx.namespace + "::" + name
|
| + value = None
|
| + if s.sy == '=':
|
| + s.next()
|
| + value = p_test(s)
|
| + items.append(Nodes.CEnumDefItemNode(pos,
|
| + name = name, cname = cname, value = value))
|
| +
|
| +def p_c_struct_or_union_definition(s, pos, ctx):
|
| + packed = False
|
| + if s.systring == 'packed':
|
| + packed = True
|
| + s.next()
|
| + if s.sy != 'IDENT' or s.systring != 'struct':
|
| + s.expected('struct')
|
| + # s.sy == ident 'struct' or 'union'
|
| + kind = s.systring
|
| + s.next()
|
| + name = p_ident(s)
|
| + cname = p_opt_cname(s)
|
| + if cname is None and ctx.namespace is not None:
|
| + cname = ctx.namespace + "::" + name
|
| + attributes = None
|
| + if s.sy == ':':
|
| + s.next()
|
| + s.expect('NEWLINE')
|
| + s.expect_indent()
|
| + attributes = []
|
| + body_ctx = Ctx()
|
| + while s.sy != 'DEDENT':
|
| + if s.sy != 'pass':
|
| + attributes.append(
|
| + p_c_func_or_var_declaration(s, s.position(), body_ctx))
|
| + else:
|
| + s.next()
|
| + s.expect_newline("Expected a newline")
|
| + s.expect_dedent()
|
| + else:
|
| + s.expect_newline("Syntax error in struct or union definition")
|
| + return Nodes.CStructOrUnionDefNode(pos,
|
| + name = name, cname = cname, kind = kind, attributes = attributes,
|
| + typedef_flag = ctx.typedef_flag, visibility = ctx.visibility,
|
| + api = ctx.api, in_pxd = ctx.level == 'module_pxd', packed = packed)
|
| +
|
| +def p_fused_definition(s, pos, ctx):
|
| + """
|
| + c(type)def fused my_fused_type:
|
| + ...
|
| + """
|
| + # s.systring == 'fused'
|
| +
|
| + if ctx.level not in ('module', 'module_pxd'):
|
| + error(pos, "Fused type definition not allowed here")
|
| +
|
| + s.next()
|
| + name = p_ident(s)
|
| +
|
| + s.expect(":")
|
| + s.expect_newline()
|
| + s.expect_indent()
|
| +
|
| + types = []
|
| + while s.sy != 'DEDENT':
|
| + if s.sy != 'pass':
|
| + #types.append(p_c_declarator(s))
|
| + types.append(p_c_base_type(s)) #, nonempty=1))
|
| + else:
|
| + s.next()
|
| +
|
| + s.expect_newline()
|
| +
|
| + s.expect_dedent()
|
| +
|
| + if not types:
|
| + error(pos, "Need at least one type")
|
| +
|
| + return Nodes.FusedTypeNode(pos, name=name, types=types)
|
| +
|
| +def p_struct_enum(s, pos, ctx):
|
| + if s.systring == 'enum':
|
| + return p_c_enum_definition(s, pos, ctx)
|
| + else:
|
| + return p_c_struct_or_union_definition(s, pos, ctx)
|
| +
|
| +def p_visibility(s, prev_visibility):
|
| + pos = s.position()
|
| + visibility = prev_visibility
|
| + if s.sy == 'IDENT' and s.systring in ('extern', 'public', 'readonly'):
|
| + visibility = s.systring
|
| + if prev_visibility != 'private' and visibility != prev_visibility:
|
| + s.error("Conflicting visibility options '%s' and '%s'"
|
| + % (prev_visibility, visibility), fatal=False)
|
| + s.next()
|
| + return visibility
|
| +
|
| +def p_c_modifiers(s):
|
| + if s.sy == 'IDENT' and s.systring in ('inline',):
|
| + modifier = s.systring
|
| + s.next()
|
| + return [modifier] + p_c_modifiers(s)
|
| + return []
|
| +
|
| +def p_c_func_or_var_declaration(s, pos, ctx):
|
| + cmethod_flag = ctx.level in ('c_class', 'c_class_pxd')
|
| + modifiers = p_c_modifiers(s)
|
| + base_type = p_c_base_type(s, nonempty = 1, templates = ctx.templates)
|
| + declarator = p_c_declarator(s, ctx, cmethod_flag = cmethod_flag,
|
| + assignable = 1, nonempty = 1)
|
| + declarator.overridable = ctx.overridable
|
| + if s.sy == 'IDENT' and s.systring == 'const' and ctx.level == 'cpp_class':
|
| + s.next()
|
| + is_const_method = 1
|
| + else:
|
| + is_const_method = 0
|
| + if s.sy == ':':
|
| + if ctx.level not in ('module', 'c_class', 'module_pxd', 'c_class_pxd', 'cpp_class') and not ctx.templates:
|
| + s.error("C function definition not allowed here")
|
| + doc, suite = p_suite_with_docstring(s, Ctx(level='function'))
|
| + result = Nodes.CFuncDefNode(pos,
|
| + visibility = ctx.visibility,
|
| + base_type = base_type,
|
| + declarator = declarator,
|
| + body = suite,
|
| + doc = doc,
|
| + modifiers = modifiers,
|
| + api = ctx.api,
|
| + overridable = ctx.overridable,
|
| + is_const_method = is_const_method)
|
| + else:
|
| + #if api:
|
| + # s.error("'api' not allowed with variable declaration")
|
| + if is_const_method:
|
| + declarator.is_const_method = is_const_method
|
| + declarators = [declarator]
|
| + while s.sy == ',':
|
| + s.next()
|
| + if s.sy == 'NEWLINE':
|
| + break
|
| + declarator = p_c_declarator(s, ctx, cmethod_flag = cmethod_flag,
|
| + assignable = 1, nonempty = 1)
|
| + declarators.append(declarator)
|
| + doc_line = s.start_line + 1
|
| + s.expect_newline("Syntax error in C variable declaration")
|
| + if ctx.level in ('c_class', 'c_class_pxd') and s.start_line == doc_line:
|
| + doc = p_doc_string(s)
|
| + else:
|
| + doc = None
|
| + result = Nodes.CVarDefNode(pos,
|
| + visibility = ctx.visibility,
|
| + base_type = base_type,
|
| + declarators = declarators,
|
| + in_pxd = ctx.level in ('module_pxd', 'c_class_pxd'),
|
| + doc = doc,
|
| + api = ctx.api,
|
| + modifiers = modifiers,
|
| + overridable = ctx.overridable)
|
| + return result
|
| +
|
| +def p_ctypedef_statement(s, ctx):
|
| + # s.sy == 'ctypedef'
|
| + pos = s.position()
|
| + s.next()
|
| + visibility = p_visibility(s, ctx.visibility)
|
| + api = p_api(s)
|
| + ctx = ctx(typedef_flag = 1, visibility = visibility)
|
| + if api:
|
| + ctx.api = 1
|
| + if s.sy == 'class':
|
| + return p_c_class_definition(s, pos, ctx)
|
| + elif s.sy == 'IDENT' and s.systring in struct_enum_union:
|
| + return p_struct_enum(s, pos, ctx)
|
| + elif s.sy == 'IDENT' and s.systring == 'fused':
|
| + return p_fused_definition(s, pos, ctx)
|
| + else:
|
| + base_type = p_c_base_type(s, nonempty = 1)
|
| + declarator = p_c_declarator(s, ctx, is_type = 1, nonempty = 1)
|
| + s.expect_newline("Syntax error in ctypedef statement")
|
| + return Nodes.CTypeDefNode(
|
| + pos, base_type = base_type,
|
| + declarator = declarator,
|
| + visibility = visibility, api = api,
|
| + in_pxd = ctx.level == 'module_pxd')
|
| +
|
| +def p_decorators(s):
|
| + decorators = []
|
| + while s.sy == 'DECORATOR':
|
| + pos = s.position()
|
| + s.next()
|
| + decstring = p_dotted_name(s, as_allowed=0)[2]
|
| + names = decstring.split('.')
|
| + decorator = ExprNodes.NameNode(pos, name=EncodedString(names[0]))
|
| + for name in names[1:]:
|
| + decorator = ExprNodes.AttributeNode(pos,
|
| + attribute=EncodedString(name),
|
| + obj=decorator)
|
| + if s.sy == '(':
|
| + decorator = p_call(s, decorator)
|
| + decorators.append(Nodes.DecoratorNode(pos, decorator=decorator))
|
| + s.expect_newline("Expected a newline after decorator")
|
| + return decorators
|
| +
|
| +def p_def_statement(s, decorators=None):
|
| + # s.sy == 'def'
|
| + pos = s.position()
|
| + s.next()
|
| + name = EncodedString( p_ident(s) )
|
| + s.expect('(')
|
| + args, star_arg, starstar_arg = p_varargslist(s, terminator=')')
|
| + s.expect(')')
|
| + if p_nogil(s):
|
| + error(pos, "Python function cannot be declared nogil")
|
| + return_type_annotation = None
|
| + if s.sy == '->':
|
| + s.next()
|
| + return_type_annotation = p_test(s)
|
| + doc, body = p_suite_with_docstring(s, Ctx(level='function'))
|
| + return Nodes.DefNode(pos, name = name, args = args,
|
| + star_arg = star_arg, starstar_arg = starstar_arg,
|
| + doc = doc, body = body, decorators = decorators,
|
| + return_type_annotation = return_type_annotation)
|
| +
|
| +def p_varargslist(s, terminator=')', annotated=1):
|
| + args = p_c_arg_list(s, in_pyfunc = 1, nonempty_declarators = 1,
|
| + annotated = annotated)
|
| + star_arg = None
|
| + starstar_arg = None
|
| + if s.sy == '*':
|
| + s.next()
|
| + if s.sy == 'IDENT':
|
| + star_arg = p_py_arg_decl(s, annotated=annotated)
|
| + if s.sy == ',':
|
| + s.next()
|
| + args.extend(p_c_arg_list(s, in_pyfunc = 1,
|
| + nonempty_declarators = 1, kw_only = 1, annotated = annotated))
|
| + elif s.sy != terminator:
|
| + s.error("Syntax error in Python function argument list")
|
| + if s.sy == '**':
|
| + s.next()
|
| + starstar_arg = p_py_arg_decl(s, annotated=annotated)
|
| + return (args, star_arg, starstar_arg)
|
| +
|
| +def p_py_arg_decl(s, annotated = 1):
|
| + pos = s.position()
|
| + name = p_ident(s)
|
| + annotation = None
|
| + if annotated and s.sy == ':':
|
| + s.next()
|
| + annotation = p_test(s)
|
| + return Nodes.PyArgDeclNode(pos, name = name, annotation = annotation)
|
| +
|
| +def p_class_statement(s, decorators):
|
| + # s.sy == 'class'
|
| + pos = s.position()
|
| + s.next()
|
| + class_name = EncodedString( p_ident(s) )
|
| + class_name.encoding = s.source_encoding
|
| + arg_tuple = None
|
| + keyword_dict = None
|
| + starstar_arg = None
|
| + if s.sy == '(':
|
| + positional_args, keyword_args, star_arg, starstar_arg = \
|
| + p_call_parse_args(s, allow_genexp = False)
|
| + arg_tuple, keyword_dict = p_call_build_packed_args(
|
| + pos, positional_args, keyword_args, star_arg, None)
|
| + if arg_tuple is None:
|
| + # XXX: empty arg_tuple
|
| + arg_tuple = ExprNodes.TupleNode(pos, args=[])
|
| + doc, body = p_suite_with_docstring(s, Ctx(level='class'))
|
| + return Nodes.PyClassDefNode(
|
| + pos, name=class_name,
|
| + bases=arg_tuple,
|
| + keyword_args=keyword_dict,
|
| + starstar_arg=starstar_arg,
|
| + doc=doc, body=body, decorators=decorators,
|
| + force_py3_semantics=s.context.language_level >= 3)
|
| +
|
| +def p_c_class_definition(s, pos, ctx):
|
| + # s.sy == 'class'
|
| + s.next()
|
| + module_path = []
|
| + class_name = p_ident(s)
|
| + while s.sy == '.':
|
| + s.next()
|
| + module_path.append(class_name)
|
| + class_name = p_ident(s)
|
| + if module_path and ctx.visibility != 'extern':
|
| + error(pos, "Qualified class name only allowed for 'extern' C class")
|
| + if module_path and s.sy == 'IDENT' and s.systring == 'as':
|
| + s.next()
|
| + as_name = p_ident(s)
|
| + else:
|
| + as_name = class_name
|
| + objstruct_name = None
|
| + typeobj_name = None
|
| + base_class_module = None
|
| + base_class_name = None
|
| + if s.sy == '(':
|
| + s.next()
|
| + base_class_path = [p_ident(s)]
|
| + while s.sy == '.':
|
| + s.next()
|
| + base_class_path.append(p_ident(s))
|
| + if s.sy == ',':
|
| + s.error("C class may only have one base class", fatal=False)
|
| + s.expect(')')
|
| + base_class_module = ".".join(base_class_path[:-1])
|
| + base_class_name = base_class_path[-1]
|
| + if s.sy == '[':
|
| + if ctx.visibility not in ('public', 'extern') and not ctx.api:
|
| + error(s.position(), "Name options only allowed for 'public', 'api', or 'extern' C class")
|
| + objstruct_name, typeobj_name = p_c_class_options(s)
|
| + if s.sy == ':':
|
| + if ctx.level == 'module_pxd':
|
| + body_level = 'c_class_pxd'
|
| + else:
|
| + body_level = 'c_class'
|
| + doc, body = p_suite_with_docstring(s, Ctx(level=body_level))
|
| + else:
|
| + s.expect_newline("Syntax error in C class definition")
|
| + doc = None
|
| + body = None
|
| + if ctx.visibility == 'extern':
|
| + if not module_path:
|
| + error(pos, "Module name required for 'extern' C class")
|
| + if typeobj_name:
|
| + error(pos, "Type object name specification not allowed for 'extern' C class")
|
| + elif ctx.visibility == 'public':
|
| + if not objstruct_name:
|
| + error(pos, "Object struct name specification required for 'public' C class")
|
| + if not typeobj_name:
|
| + error(pos, "Type object name specification required for 'public' C class")
|
| + elif ctx.visibility == 'private':
|
| + if ctx.api:
|
| + if not objstruct_name:
|
| + error(pos, "Object struct name specification required for 'api' C class")
|
| + if not typeobj_name:
|
| + error(pos, "Type object name specification required for 'api' C class")
|
| + else:
|
| + error(pos, "Invalid class visibility '%s'" % ctx.visibility)
|
| + return Nodes.CClassDefNode(pos,
|
| + visibility = ctx.visibility,
|
| + typedef_flag = ctx.typedef_flag,
|
| + api = ctx.api,
|
| + module_name = ".".join(module_path),
|
| + class_name = class_name,
|
| + as_name = as_name,
|
| + base_class_module = base_class_module,
|
| + base_class_name = base_class_name,
|
| + objstruct_name = objstruct_name,
|
| + typeobj_name = typeobj_name,
|
| + in_pxd = ctx.level == 'module_pxd',
|
| + doc = doc,
|
| + body = body)
|
| +
|
| +def p_c_class_options(s):
|
| + objstruct_name = None
|
| + typeobj_name = None
|
| + s.expect('[')
|
| + while 1:
|
| + if s.sy != 'IDENT':
|
| + break
|
| + if s.systring == 'object':
|
| + s.next()
|
| + objstruct_name = p_ident(s)
|
| + elif s.systring == 'type':
|
| + s.next()
|
| + typeobj_name = p_ident(s)
|
| + if s.sy != ',':
|
| + break
|
| + s.next()
|
| + s.expect(']', "Expected 'object' or 'type'")
|
| + return objstruct_name, typeobj_name
|
| +
|
| +
|
| +def p_property_decl(s):
|
| + pos = s.position()
|
| + s.next() # 'property'
|
| + name = p_ident(s)
|
| + doc, body = p_suite_with_docstring(
|
| + s, Ctx(level='property'), with_doc_only=True)
|
| + return Nodes.PropertyNode(pos, name=name, doc=doc, body=body)
|
| +
|
| +
|
| +def p_ignorable_statement(s):
|
| + """
|
| + Parses any kind of ignorable statement that is allowed in .pxd files.
|
| + """
|
| + if s.sy == 'BEGIN_STRING':
|
| + pos = s.position()
|
| + string_node = p_atom(s)
|
| + if s.sy != 'EOF':
|
| + s.expect_newline("Syntax error in string")
|
| + return Nodes.ExprStatNode(pos, expr=string_node)
|
| + return None
|
| +
|
| +
|
| +def p_doc_string(s):
|
| + if s.sy == 'BEGIN_STRING':
|
| + pos = s.position()
|
| + kind, bytes_result, unicode_result = p_cat_string_literal(s)
|
| + if s.sy != 'EOF':
|
| + s.expect_newline("Syntax error in doc string")
|
| + if kind in ('u', ''):
|
| + return unicode_result
|
| + warning(pos, "Python 3 requires docstrings to be unicode strings")
|
| + return bytes_result
|
| + else:
|
| + return None
|
| +
|
| +
|
| +def _extract_docstring(node):
|
| + """
|
| + Extract a docstring from a statement or from the first statement
|
| + in a list. Remove the statement if found. Return a tuple
|
| + (plain-docstring or None, node).
|
| + """
|
| + doc_node = None
|
| + if node is None:
|
| + pass
|
| + elif isinstance(node, Nodes.ExprStatNode):
|
| + if node.expr.is_string_literal:
|
| + doc_node = node.expr
|
| + node = Nodes.StatListNode(node.pos, stats=[])
|
| + elif isinstance(node, Nodes.StatListNode) and node.stats:
|
| + stats = node.stats
|
| + if isinstance(stats[0], Nodes.ExprStatNode):
|
| + if stats[0].expr.is_string_literal:
|
| + doc_node = stats[0].expr
|
| + del stats[0]
|
| +
|
| + if doc_node is None:
|
| + doc = None
|
| + elif isinstance(doc_node, ExprNodes.BytesNode):
|
| + warning(node.pos,
|
| + "Python 3 requires docstrings to be unicode strings")
|
| + doc = doc_node.value
|
| + elif isinstance(doc_node, ExprNodes.StringNode):
|
| + doc = doc_node.unicode_value
|
| + if doc is None:
|
| + doc = doc_node.value
|
| + else:
|
| + doc = doc_node.value
|
| + return doc, node
|
| +
|
| +
|
| +def p_code(s, level=None, ctx=Ctx):
|
| + body = p_statement_list(s, ctx(level = level), first_statement = 1)
|
| + if s.sy != 'EOF':
|
| + s.error("Syntax error in statement [%s,%s]" % (
|
| + repr(s.sy), repr(s.systring)))
|
| + return body
|
| +
|
| +_match_compiler_directive_comment = cython.declare(object, re.compile(
|
| + r"^#\s*cython\s*:\s*((\w|[.])+\s*=.*)$").match)
|
| +
|
| +def p_compiler_directive_comments(s):
|
| + result = {}
|
| + while s.sy == 'commentline':
|
| + m = _match_compiler_directive_comment(s.systring)
|
| + if m:
|
| + directives = m.group(1).strip()
|
| + try:
|
| + result.update(Options.parse_directive_list(
|
| + directives, ignore_unknown=True))
|
| + except ValueError, e:
|
| + s.error(e.args[0], fatal=False)
|
| + s.next()
|
| + return result
|
| +
|
| +def p_module(s, pxd, full_module_name, ctx=Ctx):
|
| + pos = s.position()
|
| +
|
| + directive_comments = p_compiler_directive_comments(s)
|
| + s.parse_comments = False
|
| +
|
| + if 'language_level' in directive_comments:
|
| + s.context.set_language_level(directive_comments['language_level'])
|
| +
|
| + doc = p_doc_string(s)
|
| + if pxd:
|
| + level = 'module_pxd'
|
| + else:
|
| + level = 'module'
|
| +
|
| + body = p_statement_list(s, ctx(level=level), first_statement = 1)
|
| + if s.sy != 'EOF':
|
| + s.error("Syntax error in statement [%s,%s]" % (
|
| + repr(s.sy), repr(s.systring)))
|
| + return ModuleNode(pos, doc = doc, body = body,
|
| + full_module_name = full_module_name,
|
| + directive_comments = directive_comments)
|
| +
|
| +def p_cpp_class_definition(s, pos, ctx):
|
| + # s.sy == 'cppclass'
|
| + s.next()
|
| + module_path = []
|
| + class_name = p_ident(s)
|
| + cname = p_opt_cname(s)
|
| + if cname is None and ctx.namespace is not None:
|
| + cname = ctx.namespace + "::" + class_name
|
| + if s.sy == '.':
|
| + error(pos, "Qualified class name not allowed C++ class")
|
| + if s.sy == '[':
|
| + s.next()
|
| + templates = [p_ident(s)]
|
| + while s.sy == ',':
|
| + s.next()
|
| + templates.append(p_ident(s))
|
| + s.expect(']')
|
| + else:
|
| + templates = None
|
| + if s.sy == '(':
|
| + s.next()
|
| + base_classes = [p_c_base_type(s, templates = templates)]
|
| + while s.sy == ',':
|
| + s.next()
|
| + base_classes.append(p_c_base_type(s, templates = templates))
|
| + s.expect(')')
|
| + else:
|
| + base_classes = []
|
| + if s.sy == '[':
|
| + error(s.position(), "Name options not allowed for C++ class")
|
| + nogil = p_nogil(s)
|
| + if s.sy == ':':
|
| + s.next()
|
| + s.expect('NEWLINE')
|
| + s.expect_indent()
|
| + attributes = []
|
| + body_ctx = Ctx(visibility = ctx.visibility, level='cpp_class', nogil=nogil or ctx.nogil)
|
| + body_ctx.templates = templates
|
| + while s.sy != 'DEDENT':
|
| + if s.systring == 'cppclass':
|
| + attributes.append(
|
| + p_cpp_class_definition(s, s.position(), body_ctx))
|
| + elif s.sy != 'pass':
|
| + attributes.append(
|
| + p_c_func_or_var_declaration(s, s.position(), body_ctx))
|
| + else:
|
| + s.next()
|
| + s.expect_newline("Expected a newline")
|
| + s.expect_dedent()
|
| + else:
|
| + attributes = None
|
| + s.expect_newline("Syntax error in C++ class definition")
|
| + return Nodes.CppClassNode(pos,
|
| + name = class_name,
|
| + cname = cname,
|
| + base_classes = base_classes,
|
| + visibility = ctx.visibility,
|
| + in_pxd = ctx.level == 'module_pxd',
|
| + attributes = attributes,
|
| + templates = templates)
|
| +
|
| +
|
| +
|
| +#----------------------------------------------
|
| +#
|
| +# Debugging
|
| +#
|
| +#----------------------------------------------
|
| +
|
| +def print_parse_tree(f, node, level, key = None):
|
| + from types import ListType, TupleType
|
| + from Nodes import Node
|
| + ind = " " * level
|
| + if node:
|
| + f.write(ind)
|
| + if key:
|
| + f.write("%s: " % key)
|
| + t = type(node)
|
| + if t is tuple:
|
| + f.write("(%s @ %s\n" % (node[0], node[1]))
|
| + for i in xrange(2, len(node)):
|
| + print_parse_tree(f, node[i], level+1)
|
| + f.write("%s)\n" % ind)
|
| + return
|
| + elif isinstance(node, Node):
|
| + try:
|
| + tag = node.tag
|
| + except AttributeError:
|
| + tag = node.__class__.__name__
|
| + f.write("%s @ %s\n" % (tag, node.pos))
|
| + for name, value in node.__dict__.items():
|
| + if name != 'tag' and name != 'pos':
|
| + print_parse_tree(f, value, level+1, name)
|
| + return
|
| + elif t is list:
|
| + f.write("[\n")
|
| + for i in xrange(len(node)):
|
| + print_parse_tree(f, node[i], level+1)
|
| + f.write("%s]\n" % ind)
|
| + return
|
| + f.write("%s%s\n" % (ind, node))
|
|
|