Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

add support for typed function parameters #140

Closed
Closed
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
Expand Up @@ -3,3 +3,5 @@
*.swo
__pycache__
.coverage
.pytest_cache/
baron.egg-info/
35 changes: 32 additions & 3 deletions baron/grammator.py
Original file line number Diff line number Diff line change
Expand Up @@ -413,9 +413,9 @@ def decorator_call(pack):
"formatting": at.hidden_tokens_after,
}] + endl

@pg.production("funcdef : async_maybe DEF NAME LEFT_PARENTHESIS parameters RIGHT_PARENTHESIS COLON suite")
@pg.production("funcdef : async_maybe DEF NAME LEFT_PARENTHESIS typed_parameters RIGHT_PARENTHESIS COLON suite")
def function_definition(pack):
(async_maybe, def_, name, left_parenthesis, parameters, right_parenthesis, colon, suite) = pack
(async_maybe, def_, name, left_parenthesis, typed_parameters, right_parenthesis, colon, suite) = pack

if async_maybe["async"] and async_maybe["value"] != "async":
raise ParsingError("The only possible keyword before a 'def' is 'async', not '%s'" % async_maybe["value"])
Expand All @@ -432,23 +432,26 @@ def function_definition(pack):
"fourth_formatting": right_parenthesis.hidden_tokens_before,
"fifth_formatting": colon.hidden_tokens_before,
"sixth_formatting": colon.hidden_tokens_after,
"arguments": parameters,
"arguments": typed_parameters,
"value": suite,
}]

@pg.production("argslist : argslist argument")
@pg.production("typed_parameters : typed_parameters typed_parameter")
@pg.production("parameters : parameters parameter")
def parameters_parameters_parameter(pack,):
(parameters, parameter,) = pack
return parameters + parameter

@pg.production("argslist : argument")
@pg.production("typed_parameters : typed_parameter")
@pg.production("parameters : parameter")
def parameters_parameter(pack,):
(parameter,) = pack
return parameter

@pg.production("argument :")
@pg.production("typed_parameter : ")
@pg.production("parameter : ")
def parameter_empty(p):
return []
Expand All @@ -461,6 +464,26 @@ def name(pack):
"value": name_.value,
}

@pg.production("typed_name : NAME COLON test")
def typed_name_with_type(pack):
(name_, colon, test) = pack
return {
"type": "typed_name",
"first_formatting": colon.hidden_tokens_before if colon else [],
"second_formatting": colon.hidden_tokens_after if colon else [],
"value": name_.value,
"annotation": test
}

@pg.production("typed_name : NAME")
def typed_name_no_type(pack):
(name_,) = pack
return {
"type": "name",
"value": name_.value,
}

@pg.production("typed_parameter : LEFT_PARENTHESIS name RIGHT_PARENTHESIS maybe_test")
@pg.production("parameter : LEFT_PARENTHESIS name RIGHT_PARENTHESIS maybe_test")
def parameter_fpdef(pack):
(left_parenthesis, name, right_parenthesis, (equal, test)) = pack
Expand All @@ -480,6 +503,7 @@ def parameter_fpdef(pack):
}]


@pg.production("typed_parameter : LEFT_PARENTHESIS fplist RIGHT_PARENTHESIS maybe_test")
@pg.production("parameter : LEFT_PARENTHESIS fplist RIGHT_PARENTHESIS maybe_test")
def parameter_fplist(pack):
(left_parenthesis, fplist, right_parenthesis, (equal, test)) = pack
Expand Down Expand Up @@ -531,6 +555,7 @@ def named_argument(pack):
"target": name if equal else {}
}]

@pg.production("typed_parameter : typed_name maybe_test")
@pg.production("parameter : name maybe_test")
def parameter_with_default(pack):
(name, (equal, test)) = pack
Expand Down Expand Up @@ -578,6 +603,7 @@ def argument_star_star(pack):
}]

# TODO refactor those 2 to standardize with argument_star and argument_star_star
@pg.production("typed_parameter : STAR NAME")
@pg.production("parameter : STAR NAME")
def parameter_star(pack):
(star, name,) = pack
Expand All @@ -591,6 +617,7 @@ def parameter_star(pack):
}]

# TODO refactor those 2 to standardize with argument_star and argument_star_star
@pg.production("typed_parameter : STAR")
@pg.production("parameter : STAR")
def parameter_star_only(pack):
(star, ) = pack
Expand All @@ -599,6 +626,7 @@ def parameter_star_only(pack):
"formatting": star.hidden_tokens_after,
}]

@pg.production("typed_parameter : DOUBLE_STAR NAME")
@pg.production("parameter : DOUBLE_STAR NAME")
def parameter_star_star(pack):
(double_star, name,) = pack
Expand All @@ -612,6 +640,7 @@ def parameter_star_star(pack):
}]

@pg.production("argument : comma")
@pg.production("typed_parameter : comma")
@pg.production("parameter : comma")
def parameter_comma(pack):
(comma,) = pack
Expand Down
6 changes: 6 additions & 0 deletions baron/grammator_primitives.py
Original file line number Diff line number Diff line change
Expand Up @@ -260,6 +260,12 @@ def names_name(pack):
return [create_node_from_token(name)]


@pg.production("names : NAME")
def names_name(pack):
(name,) = pack
return [create_node_from_token(name)]


@pg.production("names : names comma name")
def names_names_name(pack):
(names, comma, name,) = pack
Expand Down
7 changes: 7 additions & 0 deletions baron/render.py
Original file line number Diff line number Diff line change
Expand Up @@ -730,6 +730,13 @@ def child_by_key(node, key):
("formatting", "second_formatting", "target"),
("string", "target", "target"),
],
"typed_name": [
("string", "value", True),
("formatting", "first_formatting", True),
("constant", ":", True),
("formatting", "second_formatting", True),
("key", "annotation", True),
],

"print": [
("constant", "print", True),
Expand Down
6 changes: 5 additions & 1 deletion grammar/baron_grammar
Original file line number Diff line number Diff line change
Expand Up @@ -17,12 +17,16 @@ decorator: '@' dotted_name [ '(' [arglist] ')' ] NEWLINE
decorators: decorator+
decorated: decorators (classdef | funcdef)
funcdef: 'def' NAME parameters ':' suite
parameters: '(' [varargslist] ')'
parameters: '(' [typedargslist] ')'
typedargslist: ((tfpdef ['=' test] ',')*
('*' NAME [',' '**' NAME] | '**' NAME) |
tfpdef ['=' test] (',' tfpdef ['=' test])* [','])
varargslist: ((fpdef ['=' test] ',')*
('*' NAME [',' '**' NAME] | '**' NAME) |
fpdef ['=' test] (',' fpdef ['=' test])* [','])
fpdef: NAME | '(' fplist ')'
fplist: fpdef (',' fpdef)* [',']
tfpdef: NAME [':' test] | '(' fplist ')'

stmt: simple_stmt | compound_stmt
simple_stmt: small_stmt (';' small_stmt)* [';'] NEWLINE
Expand Down
178 changes: 178 additions & 0 deletions tests/test_grammator.py
Original file line number Diff line number Diff line change
Expand Up @@ -581,6 +581,73 @@ def a ( x ) :
}
])

def test_funcdef_stmt_one_parameter_typed_indent():
"""
def a ( x : int ) :
pass
"""
parse_multi([
('DEF', 'def', [], [('SPACE', ' ')]),
('NAME', 'a'),
('LEFT_PARENTHESIS', '(', [('SPACE', ' ')], [('SPACE', ' ')]),
('NAME', 'x'),
('COLON', ':', [('SPACE', ' ')], [('SPACE', ' ')]),
('NAME', 'int'),
('RIGHT_PARENTHESIS', ')', [('SPACE', ' ')]),
('COLON', ':', [('SPACE', ' ')]),
('ENDL', '\n', [], [('SPACE', ' ')]),
('INDENT', ''),
('PASS', 'pass'),
('ENDL', '\n'),
('DEDENT', ''),
], [
{
"type": "def",
"name": "a",
"decorators": [],
"async": False,
"async_formatting": [],
"first_formatting": [{"type": "space", "value": " "}],
"second_formatting": [{"type": "space", "value": " "}],
"third_formatting": [{"type": "space", "value": " "}],
"fourth_formatting": [{"type": "space", "value": " "}],
"fifth_formatting": [{"type": "space", "value": " "}],
"sixth_formatting": [],
"arguments": [
{
"type": "def_argument",
"first_formatting": [],
"second_formatting": [],
"target": {
"type": "typed_name",
"annotation": {"type": "name", "value": "int"},
"first_formatting": [{"type": "space", "value": " "}],
"second_formatting": [{"type": "space", "value": " "}],
"value": "x",
},
"value": {},
}
],
"value": [
{
"type": "endl",
"value": "\n",
"formatting": [],
"indent": " "
},
{
"type": "pass",
},
{
"type": "endl",
"formatting": [],
"indent": "",
"value": "\n"
}
],
}
])

def test_funcdef_stmt_one_parameter_comma_indent():
"""
def a ( x , ) :
Expand Down Expand Up @@ -723,6 +790,117 @@ def a ( x=1 , ) :
}
])

def test_funcdef_stmt_two_parameters_typed_with_default_indent():
"""
def a ( x : int = 1 , y : List[str] ) :
pass
"""
parse_multi([
('DEF', 'def', [], [('SPACE', ' ')]),
('NAME', 'a'),
('LEFT_PARENTHESIS', '(', [('SPACE', ' ')], [('SPACE', ' ')]),
('NAME', 'x'),
('COLON', ':', [('SPACE', ' ')], [('SPACE', ' ')]),
('NAME', 'int'),
('EQUAL', '=', [('SPACE', ' ')], [('SPACE', ' ')]),
('INT', '1'),
('COMMA', ',', [('SPACE', ' ')], [('SPACE', ' ')]),
('NAME', 'y'),
('COLON', ':', [('SPACE', ' ')], [('SPACE', ' ')]),
('NAME', 'List'),
('LEFT_SQUARE_BRACKET', '[', [], []),
('NAME', 'str'),
('RIGHT_SQUARE_BRACKET', '[', [], []),
('RIGHT_PARENTHESIS', ')', [('SPACE', ' ')]),
('COLON', ':', [('SPACE', ' ')]),
('ENDL', '\n', [], [('SPACE', ' ')]),
('INDENT', ''),
('PASS', 'pass'),
('ENDL', '\n'),
('DEDENT', ''),
], [
{
"type": "def",
"name": "a",
"decorators": [],
"async": False,
"async_formatting": [],
"first_formatting": [{"type": "space", "value": " "}],
"second_formatting": [{"type": "space", "value": " "}],
"third_formatting": [{"type": "space", "value": " "}],
"fourth_formatting": [{"type": "space", "value": " "}],
"fifth_formatting": [{"type": "space", "value": " "}],
"sixth_formatting": [],
"arguments": [
{
"type": "def_argument",
"first_formatting": [{"type": "space", "value": " "}],
"second_formatting": [{"type": "space", "value": " "}],
"target": {
"type": "typed_name",
"annotation": {"type": "name", "value": "int"},
"first_formatting": [{"type": "space", "value": " "}],
"second_formatting": [{"type": "space", "value": " "}],
"value": "x",
},
"value": {"section": "number", "type": "int", "value": "1"},
},
{
"type": "comma",
"first_formatting": [{"type": "space", "value": " "}],
"second_formatting": [{"type": "space", "value": " "}],
},
{
"type": "def_argument",
"first_formatting": [],
"second_formatting": [],
"target": {
"type": "typed_name",
"annotation":
{
"type": "atomtrailers",
"value": [
{
"type": "name",
"value": "List",
},
{
"type": "getitem",
"first_formatting": [],
"second_formatting": [],
"third_formatting": [],
"fourth_formatting": [],
"value": {"type": "name", "value": "str"},
}
]
},
"first_formatting": [{"type": "space", "value": " "}],
"second_formatting": [{"type": "space", "value": " "}],
"value": "y",
},
"value": {},
},
],
"value": [
{
"type": "endl",
"value": "\n",
"formatting": [],
"indent": " "
},
{
"type": "pass",
},
{
"type": "endl",
"formatting": [],
"indent": "",
"value": "\n"
}
],
}
])

def test_class_empty():
"""
class A:
Expand Down