Skip to content

Commit

Permalink
95% grammar coverage.
Browse files Browse the repository at this point in the history
To go further it will be necessary to implement true LL(1) lookahead.
whitequark committed May 7, 2015
1 parent a4ede46 commit f671204
Showing 3 changed files with 361 additions and 58 deletions.
34 changes: 23 additions & 11 deletions pyparser/ast.py
Original file line number Diff line number Diff line change
@@ -15,6 +15,8 @@
from .shim import ast
from .shim.ast import AST

# Location mixins

class commonloc(object):
"""
A mixin common for all nodes.
@@ -61,17 +63,21 @@ class beginendloc(commonloc):
"""
_locs = commonloc._locs + ('begin_loc', 'end_loc')

class alias(commonloc):
# AST nodes

class alias(commonloc, ast.alias):
"""
An import alias, e.g. ``x as y``.
:ivar name: (string) value to import
:ivar asname: (string) name to add to the environment
:ivar name_loc: location of name
:ivar as_loc: location of ``as``
:ivar asname_loc: location of asname
"""
_locs = commonloc._locs + ('as_loc',)
_locs = commonloc._locs + ('name_loc', 'as_loc', 'asname_loc')

class arguments(commonloc):
class arguments(beginendloc, ast.arguments):
"""
Function definition arguments, e.g. in ``def f(x, y=1, *z, **t)``.
@@ -85,6 +91,8 @@ class arguments(commonloc):
:ivar kwarg_loc: location of keyword splat formal argument, if any
:ivar default_equals_locs: locations of ``=``
"""
_locs = beginendloc._locs + ('star_loc', 'vararg_loc', 'dstar_loc',
'vararg_loc', 'kwarg_loc', 'default_equals_locs')

class boolop:
"""
@@ -241,10 +249,10 @@ class Lambda(expr, ast.Lambda):
:ivar args: (:class:`arguments`) arguments
:ivar body: (node) body
:ivar keyword_loc: location of ``lambda``
:ivar lambda_loc: location of ``lambda``
:ivar colon_loc: location of ``:``
"""
_locs = expr._locs + ('keyword_loc', 'colon_loc')
_locs = expr._locs + ('lambda_loc', 'colon_loc')
class List(beginendloc, expr, ast.List):
"""
A list, e.g. ``[x, y]``.
@@ -320,8 +328,9 @@ class Yield(expr, ast.Yield):
A yield expression, e.g. ``(yield x)``.
:ivar value: (node) yielded value
:ivar yield_loc: location of ``yield``
"""
_locs = expr._locs + ('keyword_loc',)
_locs = expr._locs + ('yield_loc',)

# expr_context
# AugLoad
@@ -507,7 +516,7 @@ class FunctionDef(keywordloc, stmt, ast.FunctionDef):
:ivar colon_loc: location of ``:``, if any
:ivar at_locs: locations of decorator ``@``
"""
_locs = keywordloc._locs + ('name_loc', 'colon_loc', 'at_loc')
_locs = keywordloc._locs + ('name_loc', 'colon_loc', 'at_locs')
class Global(keywordloc, stmt, ast.Global):
"""
The ``global x, y`` statement.
@@ -534,9 +543,10 @@ class Import(keywordloc, stmt, ast.Import):
:ivar names: (list of :class:`alias`) names
"""
class ImportFrom(keywordloc, stmt, ast.Import):
class ImportFrom(keywordloc, stmt, ast.ImportFrom):
"""
The ``from ...x import y, z`` or ``from x import *`` statement.
The ``from ...x import y, z`` or ``from x import (y, z)`` or
``from x import *`` statement.
:ivar names: (list of :class:`alias`) names
:ivar module: (string) module name, if any
@@ -545,8 +555,10 @@ class ImportFrom(keywordloc, stmt, ast.Import):
:ivar dots_loc: location of dots, if any
:ivar module_loc: location of module name, if any
:ivar import_loc: location of ``import``
:ivar lparen_loc: location of ``(``, if any
:ivar rparen_loc: location of ``)``, if any
"""
_locs = keywordloc._locs + ('module_loc', 'import_loc')
_locs = keywordloc._locs + ('dots_loc', 'module_loc', 'import_loc', 'lparen_loc', 'rparen_loc')
class Pass(keywordloc, stmt, ast.Pass):
"""The ``pass`` statement."""
class Print(keywordloc, stmt, ast.Print):
@@ -582,7 +594,7 @@ class TryExcept(keywordloc, stmt, ast.TryExcept):
:ivar else_colon_loc: location of ``:`` after ``else``
"""
_locs = keywordloc._locs + ('try_colon_loc', 'else_loc', 'else_colon_loc',)
class TryFinally(keywordloc, stmt, ast.TryExcept):
class TryFinally(keywordloc, stmt, ast.TryFinally):
"""
The ``try:· x·finally:· y`` statement.
130 changes: 86 additions & 44 deletions pyparser/parser.py
Original file line number Diff line number Diff line change
@@ -280,7 +280,8 @@ def rule(parser, begin_loc, node, end_loc):
if node.loc is None and type(node) in [
ast.List, ast.Dict, ast.Tuple, ast.Repr,
ast.ListComp, ast.GeneratorExp,
ast.Call, ast.Subscript]:
ast.Call, ast.Subscript,
ast.arguments]:
node.begin_loc, node.end_loc, node.loc = \
begin_loc, end_loc, begin_loc.join(end_loc)
return node
@@ -318,8 +319,9 @@ def _assignable(self, node):
return node

def _empty_arguments(self):
# TODO
return None
return ast.arguments(args=[], defaults=[], vararg=None, kwarg=None,
star_loc=None, vararg_loc=None, dstar_loc=None, kwarg_loc=None,
default_equals_locs=[], begin_loc=None, end_loc=None, loc=None)

# Python-specific methods
@action(Alt(Newline(),
@@ -344,13 +346,13 @@ def eval_input(self, expr):

@action(Seq(Loc('@'), Rule('dotted_name'), Opt(BeginEnd('(', Rule('arglist'), ')')),
Loc('newline')))
def decorator(at_loc, dotted_name, call_opt, newline_loc):
def decorator(self, at_loc, dotted_name, call_opt, newline_loc):
"""decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE"""
name_loc, name = dotted_name
expr = ast.Name(id=name, loc=name_loc)
expr = ast.Name(id=name, ctx=None, loc=name_loc)
if call_opt:
call_opt.func = expr
call_opt.loc = name_loc.join(arglist_opt.loc)
call_opt.loc = name_loc.join(call_opt.loc)
expr = call_opt
return at_loc, expr

@@ -361,16 +363,24 @@ def decorator(at_loc, dotted_name, call_opt, newline_loc):
def decorated(self, decorators, classfuncdef):
"""decorated: decorators (classdef | funcdef)"""
classfuncdef.at_locs = list(map(lambda x: x[0], decorators))
classfuncdef.decorator_list = list(map(lambda x: x[0], decorators))
classfuncdef.decorator_list = list(map(lambda x: x[1], decorators))
classfuncdef.loc = classfuncdef.loc.join(decorators[0][0])
return classfuncdef

@action(Seq(Loc('def'), Tok('ident'), Rule('parameters'), Loc(':'), Rule('suite')))
def funcdef(self, def_loc, ident_tok, args, colon_loc, suite):
"""funcdef: 'def' NAME parameters ':' suite"""
return ast.FunctionDef(name=ident_tok.value, args=args, body=suite, decorator_list=[],
keyword_loc=def_loc, name_loc=ident_tok.value, colon_loc=colon_loc)
at_locs=[], keyword_loc=def_loc, name_loc=ident_tok.loc,
colon_loc=colon_loc, loc=def_loc.join(suite[-1].loc))

@action(Opt(Rule('varargslist')))
def parameters_1(self, args):
if args is None:
args = self._empty_arguments()
return args

parameters = BeginEnd('(', Rule('varargslist'), ')')
parameters = BeginEnd('(', parameters_1, ')')
"""parameters: '(' [varargslist] ')'"""

@action(Seq(Loc('**'), Tok('ident')))
@@ -389,7 +399,7 @@ def varargslist_2(self, star_loc, vararg_tok, kwarg_opt):
star_loc=star_loc, vararg_loc=vararg_tok.loc,
dstar_loc=dstar_loc, kwarg_loc=kwarg_loc)

pass
varargslist = Tok('no')
"""varargslist: ((fpdef ['=' test] ',')*
('*' NAME [',' '**' NAME] | '**' NAME) |
fpdef ['=' test] (',' fpdef ['=' test])* [','])"""
@@ -544,7 +554,7 @@ def raise_stmt(self, raise_loc, type_opt):
def import_name(self, import_loc, names):
"""import_name: 'import' dotted_as_names"""
return ast.Import(names=names,
keyword_loc=import_loc, loc=keyword_loc.join(names[-1].loc))
keyword_loc=import_loc, loc=import_loc.join(names[-1].loc))

@action(Seq(Star(Loc('.')), Rule('dotted_name')))
def import_from_1(self, dots, dotted_name):
@@ -556,45 +566,61 @@ def import_from_2(self, dots):

@action(Loc('*'))
def import_from_3(self, star_loc):
return [ast.alias(name='*', asname=None,
name_loc=star_loc, as_loc=None, asname_loc=None, loc=star_loc)]
return None, \
[ast.alias(name='*', asname=None,
name_loc=star_loc, as_loc=None, asname_loc=None, loc=star_loc)], \
None

@action(Rule('import_as_names'))
def import_from_4(self, names):
return None, names, None

@action(Seq(Loc('from'), Alt(import_from_1, import_from_2),
Loc('import'), Alt(import_from_3,
BeginEnd('(', Rule('import_as_names'), ')'),
Rule('import_as_names'))))
Seq(Loc('('), Rule('import_as_names'), Loc(')')),
import_from_4)))
def import_from(self, from_loc, module_name, import_loc, names):
"""import_from: ('from' ('.'* dotted_name | '.'+)
'import' ('*' | '(' import_as_names ')' | import_as_names))"""
dots, (module_loc, module) = module_name
lparen_loc, names, rparen_loc = names
dots_loc = None
if dots != []:
dots_loc = dots[0].join(dots[-1])
loc = from_loc.join(names[-1].loc)
if rparen_loc:
loc = loc.join(rparen_loc)
return ast.ImportFrom(names=names, module=module, level=len(dots),
keyword_loc=from_loc, dots_loc=dots_loc, module_loc=module_loc,
import_loc=import_loc)
import_loc=import_loc, lparen_loc=lparen_loc, rparen_loc=rparen_loc,
loc=loc)

@action(Seq(Tok('ident'), Opt(Seq(Loc('as'), Tok('ident')))))
def import_as_name(self, name, as_name_opt):
def import_as_name(self, name_tok, as_name_opt):
"""import_as_name: NAME ['as' NAME]"""
asname = as_loc = None
loc = name.loc
asname_name = asname_loc = as_loc = None
loc = name_tok.loc
if as_name_opt:
asname, as_loc = as_name_opt
as_loc, asname = as_name_opt
asname_name = asname.value
asname_loc = asname.loc
loc = loc.join(asname.loc)
return ast.alias(name=name.value, asname=asname.value,
loc=loc, as_loc=as_loc)
return ast.alias(name=name_tok.value, asname=asname_name,
loc=loc, name_loc=name_tok.loc, as_loc=as_loc, asname_loc=asname_loc)

@action(Seq(Rule('dotted_name'), Opt(Seq(Loc('as'), Tok('ident')))))
def dotted_as_name(self, dotted_name, as_name_opt):
"""dotted_as_name: dotted_name ['as' NAME]"""
asname = as_loc = None
loc, name = dotted_name
asname_name = asname_loc = as_loc = None
dotted_name_loc, dotted_name_name = dotted_name
loc = dotted_name_loc
if as_name_opt:
asname, as_loc = as_name_opt
as_loc, asname = as_name_opt
asname_name = asname.value
asname_loc = asname.loc
loc = loc.join(asname.loc)
return ast.alias(name=name, asname=asname.value,
loc=loc, as_loc=as_loc)
return ast.alias(name=dotted_name_name, asname=asname_name,
loc=loc, name_loc=dotted_name_loc, as_loc=as_loc, asname_loc=asname_loc)

import_as_names = List(Rule('import_as_name'), ',', trailing=True)
"""import_as_names: import_as_name (',' import_as_name)* [',']"""
@@ -708,25 +734,31 @@ def try_stmt_1(self, clauses, else_opt, finally_opt):
handlers = []
for clause in clauses:
handler, handler.colon_loc, handler.body = clause
handler.loc = handler.loc.join(handler.body[-1].loc)
handlers.append(handler)

else_loc = else_colon_loc = orelse = None
loc = handlers[-1].loc
if else_opt:
else_loc, else_colon_loc, orelse = else_opt
loc = orelse[-1].loc

stmt = ast.TryExcept(handlers=handlers, orelse=orelse,
else_loc=else_loc, else_colon_loc=else_colon_loc)
stmt = ast.TryExcept(body=None, handlers=handlers, orelse=orelse,
else_loc=else_loc, else_colon_loc=else_colon_loc,
loc=loc)
if finally_opt:
finally_loc, finally_colon_loc, finalbody = finally_opt
return ast.TryFinally(body=[stmt], finalbody=finalbody,
finally_loc=finally_loc, finally_colon_loc=finally_colon_loc)
finally_loc=finally_loc, finally_colon_loc=finally_colon_loc,
loc=finalbody[-1].loc)
else:
return stmt

@action(Seq(Loc('finally'), Loc(':'), Rule('suite')))
def try_stmt_2(self, finally_loc, finally_colon_loc, finalbody):
return ast.TryFinally(finalbody=finalbody,
finally_loc=finally_loc, finally_colon_loc=finally_colon_loc)
return ast.TryFinally(body=None, finalbody=finalbody,
finally_loc=finally_loc, finally_colon_loc=finally_colon_loc,
loc=finalbody[-1].loc)

@action(Seq(Loc('try'), Loc(':'), Rule('suite'), Alt(try_stmt_1, try_stmt_2)))
def try_stmt(self, try_loc, try_colon_loc, body, stmt):
@@ -741,7 +773,10 @@ def try_stmt(self, try_loc, try_colon_loc, body, stmt):
if stmt.body is None: # try..finally or try..except
stmt.body = body
else: # try..except..finally
stmt.body.keyword_loc, stmt.body.try_colon_loc = try_loc, try_colon_loc
stmt.body[0].keyword_loc, stmt.body[0].try_colon_loc, stmt.body[0].body = \
try_loc, try_colon_loc, body
stmt.body[0].loc = stmt.body[0].loc.join(try_loc)
stmt.loc = stmt.loc.join(try_loc)
return stmt

@action(Seq(Loc('with'), Rule('test'), Opt(Rule('with_var')), Loc(':'), Rule('suite')))
@@ -763,12 +798,15 @@ def with_stmt(self, with_loc, context, with_var, colon_loc, body):
def except_clause(self, except_loc, exc_opt):
"""except_clause: 'except' [test [('as' | ',') test]]"""
type_ = name = as_loc = None
loc = except_loc
if exc_opt:
type_, name_opt = exc_opt
loc = loc.join(type_.loc)
if name_opt:
as_loc, name = name_opt
loc = loc.join(name.loc)
return ast.ExceptHandler(type=type_, name=name,
except_loc=except_loc, as_loc=as_loc)
except_loc=except_loc, as_loc=as_loc, loc=loc)

@action(Plus(Rule('stmt')))
def suite_1(self, stmts):
@@ -785,13 +823,15 @@ def suite_1(self, stmts):
old_test = Alt(Rule('or_test'), Rule('old_lambdef'))
"""old_test: or_test | old_lambdef"""

@action(Seq(Loc('lambda'), Opt(Rule('varargslist')), Loc(':'), Rule(old_test)))
@action(Seq(Loc('lambda'), Opt(Rule('varargslist')), Loc(':'), Rule('old_test')))
def old_lambdef(self, lambda_loc, args_opt, colon_loc, body):
"""old_lambdef: 'lambda' [varargslist] ':' old_test"""
args = self._empty_arguments() if not args_opt else args_opt
return ast.Lambda(args=args, body=body,
loc=lambda_loc.join(body.loc),
keyword_loc=lambda_loc, colon_loc=colon_loc)
if args_opt is None:
args_opt = self._empty_arguments()
args_opt.loc = colon_loc.begin()
return ast.Lambda(args=args_opt, body=body,
lambda_loc=lambda_loc, colon_loc=colon_loc,
loc=lambda_loc.join(body.loc))
# 2.x-only backwards compatibility end

@action(Seq(Rule('or_test'), Opt(Seq(Loc('if'), Rule('or_test'),
@@ -974,10 +1014,12 @@ def testlist_gexp_2(self, elts):
@action(Seq(Loc('lambda'), Opt(Rule('varargslist')), Loc(':'), Rule('test')))
def lambdef(self, lambda_loc, args_opt, colon_loc, body):
"""lambdef: 'lambda' [varargslist] ':' test"""
args = self._empty_arguments() if not args_opt else args_opt
return ast.Lambda(args=args, body=body,
loc=lambda_loc.join(body.loc),
keyword_loc=lambda_loc, colon_loc=colon_loc)
if args_opt is None:
args_opt = self._empty_arguments()
args_opt.loc = colon_loc.begin()
return ast.Lambda(args=args_opt, body=body,
lambda_loc=lambda_loc, colon_loc=colon_loc,
loc=lambda_loc.join(body.loc))

@action(Seq(Loc('.'), Tok('ident')))
def trailer_1(self, dot_loc, ident_tok):
@@ -1230,7 +1272,7 @@ def compose(comprehensions):
def yield_expr(self, stmt_loc, exprs):
"""yield_expr: 'yield' [testlist]"""
return ast.Yield(value=exprs,
loc=stmt_loc.join(exprs.loc), keyword_loc=stmt_loc)
yield_loc=stmt_loc, loc=stmt_loc.join(exprs.loc))

def for_code(code, version=(2,7)):
return Parser(lexer.Lexer(source.Buffer(code), version))
255 changes: 252 additions & 3 deletions pyparser/test/test_parser.py
Original file line number Diff line number Diff line change
@@ -51,7 +51,7 @@ def flatten_ast(self, node):
flat_node[unicode(field)] = value
return flat_node

_loc_re = re.compile(r"\s*([~^]+)\s+([a-z_0-9.]+)")
_loc_re = re.compile(r"\s*([~^]*)<?\s+([a-z_0-9.]+)")
_path_re = re.compile(r"(([a-z_]+)|([0-9]+))(\.)?")

def match_loc(self, ast, matcher, root=lambda x: x):
@@ -534,7 +534,7 @@ def test_yield_expr(self):
self.assertParsesExpr(
{'ty': 'Yield', 'value': self.ast_1},
"(yield 1)",
" ~~~~~ keyword_loc"
" ~~~~~ yield_loc"
" ~~~~~~~ loc")

def test_if_expr(self):
@@ -545,6 +545,34 @@ def test_if_expr(self):
" ~~~~ else_loc"
"~~~~~~~~~~~~~ loc")

def test_lambda(self):
self.assertParsesExpr(
{'ty': 'Lambda',
'args': {'ty': 'arguments', 'args': [], 'defaults': [],
'kwarg': None, 'vararg': None},
'body': self.ast_x},
"lambda: x",
"~~~~~~ lambda_loc"
" < args.loc"
" ^ colon_loc"
"~~~~~~~~~ loc")

def test_old_lambda(self):
self.assertParsesExpr(
{'ty': 'ListComp', 'elt': self.ast_x, 'generators': [
{'ty': 'comprehension', 'iter': self.ast_z, 'target': self.ast_y,
'ifs': [{'ty': 'Lambda',
'args': {'ty': 'arguments', 'args': [], 'defaults': [],
'kwarg': None, 'vararg': None},
'body': self.ast_t}
]}
]},
"[x for y in z if lambda: t]",
" ~~~~~~ generators.0.ifs.0.lambda_loc"
" < generators.0.ifs.0.args.loc"
" ^ generators.0.ifs.0.colon_loc"
" ~~~~~~~~~ generators.0.ifs.0.loc")

#
# CALLS, ATTRIBUTES AND SUBSCRIPTS
#
@@ -836,7 +864,7 @@ def test_yield(self):
self.assertParsesSuite(
[{'ty': 'Expr', 'value': {'ty': 'Yield', 'value': self.ast_x}}],
"yield x",
"~~~~~ 0.value.keyword_loc"
"~~~~~ 0.value.yield_loc"
"~~~~~~~ 0.value.loc"
"~~~~~~~ 0.loc")

@@ -865,6 +893,103 @@ def test_raise(self):
"~~~~~ 0.keyword_loc"
"~~~~~~~~~~~~~ 0.loc")

def test_import(self):
self.assertParsesSuite(
[{'ty': 'Import', 'names': [
{'ty': 'alias', 'name': 'foo', 'asname': None}
]}],
"import foo",
"~~~~~~ 0.keyword_loc"
" ~~~ 0.names.0.name_loc"
" ~~~ 0.names.0.loc"
"~~~~~~~~~~ 0.loc")

self.assertParsesSuite(
[{'ty': 'Import', 'names': [
{'ty': 'alias', 'name': 'foo.bar', 'asname': None}
]}],
"import foo. bar",
"~~~~~~ 0.keyword_loc"
" ~~~~~~~~ 0.names.0.name_loc"
" ~~~~~~~~ 0.names.0.loc"
"~~~~~~~~~~~~~~~ 0.loc")

self.assertParsesSuite(
[{'ty': 'Import', 'names': [
{'ty': 'alias', 'name': 'foo', 'asname': 'bar'}
]}],
"import foo as bar",
"~~~~~~ 0.keyword_loc"
" ~~~ 0.names.0.name_loc"
" ~~ 0.names.0.as_loc"
" ~~~ 0.names.0.asname_loc"
" ~~~~~~~~~~ 0.names.0.loc"
"~~~~~~~~~~~~~~~~~ 0.loc")

def test_from(self):
self.assertParsesSuite(
[{'ty': 'ImportFrom', 'names': [
{'ty': 'alias', 'name': 'foo', 'asname': None}
], 'module': 'bar', 'level': 0}],
"from bar import foo",
"~~~~ 0.keyword_loc"
" ~~~ 0.module_loc"
" ~~~~~~ 0.import_loc"
" ~~~ 0.names.0.name_loc"
" ~~~ 0.names.0.loc"
"~~~~~~~~~~~~~~~~~~~ 0.loc")

self.assertParsesSuite(
[{'ty': 'ImportFrom', 'names': [
{'ty': 'alias', 'name': 'foo', 'asname': None}
], 'module': 'bar', 'level': 2}],
"from ..bar import foo",
"~~~~ 0.keyword_loc"
" ~~ 0.dots_loc"
" ~~~ 0.module_loc"
" ~~~~~~ 0.import_loc"
" ~~~ 0.names.0.name_loc"
" ~~~ 0.names.0.loc"
"~~~~~~~~~~~~~~~~~~~~~ 0.loc")

self.assertParsesSuite(
[{'ty': 'ImportFrom', 'names': [
{'ty': 'alias', 'name': 'foo', 'asname': 'bar'}
], 'module': 'bar', 'level': 2}],
"from ..bar import foo as bar",
" ~~~ 0.names.0.name_loc"
" ~~ 0.names.0.as_loc"
" ~~~ 0.names.0.asname_loc"
" ~~~~~~~~~~ 0.names.0.loc"
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0.loc")

self.assertParsesSuite(
[{'ty': 'ImportFrom', 'names': [
{'ty': 'alias', 'name': 'foo', 'asname': None}
], 'module': 'bar', 'level': 2}],
"from ..bar import (foo)",
" ^ 0.lparen_loc"
" ~~~ 0.names.0.loc"
" ^ 0.rparen_loc"
"~~~~~~~~~~~~~~~~~~~~~~~ 0.loc")

self.assertParsesSuite(
[{'ty': 'ImportFrom', 'names': [
{'ty': 'alias', 'name': '*', 'asname': None}
], 'module': 'bar', 'level': 0}],
"from bar import *",
" ^ 0.names.0.name_loc"
" ^ 0.names.0.loc"
"~~~~~~~~~~~~~~~~~ 0.loc")

# self.assertParsesSuite(
# [{'ty': 'ImportFrom', 'names': [
# {'ty': 'alias', 'name': 'foo', 'asname': None}
# ], 'module': None, 'level': 2}],
# "from .. import foo",
# " ~~ 0.dots_loc"
# "~~~~~~~~~~~~~~~~~~ 0.loc")

def test_global(self):
self.assertParsesSuite(
[{'ty': 'Global', 'names': ['x', 'y']}],
@@ -981,6 +1106,86 @@ def test_for(self):
" ^ 0.else_colon_loc"
"~~~~~~~~~~~~~~~~~~~~~~~~~ 0.loc")

def test_try(self):
self.assertParsesSuite(
[{'ty': 'TryExcept', 'body': [self.ast_expr_1], 'orelse': None,
'handlers': [
{'ty': 'ExceptHandler', 'type': None, 'name': None,
'body': [self.ast_expr_2]}
]}],
"try:· 1·except:· 2",
"~~~ 0.keyword_loc"
" ^ 0.try_colon_loc"
" ~~~~~~ 0.handlers.0.except_loc"
" ^ 0.handlers.0.colon_loc"
" ~~~~~~~~~~~ 0.handlers.0.loc"
"~~~~~~~~~~~~~~~~~~~~ 0.loc")

self.assertParsesSuite(
[{'ty': 'TryExcept', 'body': [self.ast_expr_1], 'orelse': None,
'handlers': [
{'ty': 'ExceptHandler', 'type': self.ast_y, 'name': None,
'body': [self.ast_expr_2]}
]}],
"try:· 1·except y:· 2",
"")

self.assertParsesSuite(
[{'ty': 'TryExcept', 'body': [self.ast_expr_1], 'orelse': None,
'handlers': [
{'ty': 'ExceptHandler', 'type': self.ast_y, 'name': self.ast_t,
'body': [self.ast_expr_2]}
]}],
"try:· 1·except y as t:· 2",
" ~~ 0.handlers.0.as_loc")

self.assertParsesSuite(
[{'ty': 'TryExcept', 'body': [self.ast_expr_1], 'orelse': None,
'handlers': [
{'ty': 'ExceptHandler', 'type': self.ast_y, 'name': self.ast_t,
'body': [self.ast_expr_2]}
]}],
"try:· 1·except y, t:· 2",
" ^ 0.handlers.0.as_loc")

self.assertParsesSuite(
[{'ty': 'TryExcept', 'body': [self.ast_expr_1], 'orelse': [self.ast_expr_3],
'handlers': [
{'ty': 'ExceptHandler', 'type': None, 'name': None,
'body': [self.ast_expr_2]}
]}],
"try:· 1·except:· 2·else:· 3",
" ~~~~ 0.else_loc"
" ^ 0.else_colon_loc"
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0.loc")

def test_finally(self):
self.assertParsesSuite(
[{'ty': 'TryFinally', 'body': [self.ast_expr_1], 'finalbody': [self.ast_expr_2]}],
"try:· 1·finally:· 2",
"~~~ 0.keyword_loc"
" ^ 0.try_colon_loc"
" ~~~~~~~ 0.finally_loc"
" ^ 0.finally_colon_loc"
"~~~~~~~~~~~~~~~~~~~~~ 0.loc")

self.assertParsesSuite(
[{'ty': 'TryFinally', 'finalbody': [self.ast_expr_3], 'body': [
{'ty': 'TryExcept', 'body': [self.ast_expr_1], 'orelse': None, 'handlers': [
{'ty': 'ExceptHandler', 'type': None, 'name': None,
'body': [self.ast_expr_2]}
]}
]}],
"try:· 1·except:· 2·finally:· 3",
"~~~ 0.keyword_loc"
" ^ 0.try_colon_loc"
"~~~ 0.body.0.keyword_loc"
" ^ 0.body.0.try_colon_loc"
"~~~~~~~~~~~~~~~~~~~~ 0.body.0.loc"
" ~~~~~~~ 0.finally_loc"
" ^ 0.finally_colon_loc"
"~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 0.loc")

def test_with(self):
self.assertParsesSuite(
[{'ty': 'With', 'context_expr': self.ast_x, 'optional_vars': None,
@@ -1015,6 +1220,50 @@ def test_class(self):
" ^ 0.rparen_loc"
"~~~~~~~~~~~~~~~~~~~~~ 0.loc")

def test_func(self):
self.assertParsesSuite(
[{'ty': 'FunctionDef', 'name': 'foo',
'args': {'ty': 'arguments', 'args': [], 'defaults': [],
'kwarg': None, 'vararg': None},
'body': [{'ty': 'Pass'}], 'decorator_list': []}],
"def foo():· pass",
"~~~ 0.keyword_loc"
" ~~~ 0.name_loc"
" ^ 0.args.begin_loc"
" ^ 0.args.end_loc"
" ^ 0.colon_loc"
"~~~~~~~~~~~~~~~~~ 0.loc")

def test_decorated(self):
self.assertParsesSuite(
[{'ty': 'ClassDef', 'name': 'x', 'bases': [],
'body': [{'ty': 'Pass'}], 'decorator_list': [self.ast_x]}],
"@x·class x:· pass",
"^ 0.at_locs.0"
" ^ 0.decorator_list.0.loc"
"~~~~~~~~~~~~~~~~~~ 0.loc")

self.assertParsesSuite(
[{'ty': 'ClassDef', 'name': 'x', 'bases': [],
'body': [{'ty': 'Pass'}], 'decorator_list': [
{'ty': 'Call', 'func': self.ast_x,
'args': [self.ast_1], 'keywords': [], 'kwargs': None, 'starargs': None}
]}],
"@x(1)·class x:· pass",
"^ 0.at_locs.0"
" ~~~~ 0.decorator_list.0.loc"
"~~~~~~~~~~~~~~~~~~~~~ 0.loc")

self.assertParsesSuite(
[{'ty': 'FunctionDef', 'name': 'x',
'args': {'ty': 'arguments', 'args': [], 'defaults': [],
'kwarg': None, 'vararg': None},
'body': [{'ty': 'Pass'}], 'decorator_list': [self.ast_x]}],
"@x·def x():· pass",
"^ 0.at_locs.0"
" ^ 0.decorator_list.0.loc"
"~~~~~~~~~~~~~~~~~~ 0.loc")

#
# PARSING MODES
#

0 comments on commit f671204

Please sign in to comment.