diff --git a/CHANGELOG.md b/CHANGELOG.md index 81d09371..02d3d7a6 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -2,9 +2,14 @@ ## [master] +### Added + - Added support for multi-statement lambdas (#191) + ### Changed - Removed `private-method-call` linter check due to false positives when calling `super._foo()` - Fixed support for `get_node` syntax to accommodate for `$/(...)` + - Changed formatting of some uni-statement lambdas + - Changed formatting of multi-statement, inline lambdas ## [4.3.1] 2024-08-24 diff --git a/gdtoolkit/formatter/expression.py b/gdtoolkit/formatter/expression.py index dcc83a6c..4de7d7b2 100644 --- a/gdtoolkit/formatter/expression.py +++ b/gdtoolkit/formatter/expression.py @@ -1,4 +1,5 @@ from typing import Dict, Callable, List, Optional +from importlib import import_module from lark import Tree, Token from lark.tree import Meta @@ -149,6 +150,8 @@ def _format_foldable_to_multiple_lines( "dict": _format_dict_to_multiple_lines, "c_dict_element": _format_kv_pair_to_multiple_lines, "eq_dict_element": _format_kv_pair_to_multiple_lines, + "lambda": _format_lambda_to_multiple_lines, + "lambda_header": _format_lambda_header_to_multiple_lines, # fake expressions: "func_args": _format_args_to_multiple_lines, "func_arg_regular": _format_func_arg_to_multiple_lines, @@ -165,33 +168,6 @@ def _format_foldable_to_multiple_lines( ), "annotation": _format_annotation_to_multiple_lines, "annotation_args": _format_args_to_multiple_lines, - "inline_lambda": _format_inline_lambda_to_multiple_lines, - "lambda_header": _format_lambda_header_to_multiple_lines, - "inline_lambda_statements": _format_inline_lambda_statements_to_multiple_lines, - "pass_stmt": _format_concrete_expression_to_single_line, - "return_stmt": lambda e, ec, c: _append_to_expression_context_and_pass_standalone( - "return ", e.children[0], ec, c - ), - "expr_stmt": lambda e, ec, c: _format_standalone_expression( - e.children[0].children[0], ec, c - ), - "func_var_stmt": lambda e, ec, c: _format_standalone_expression( - e.children[0], ec, c - ), - "func_var_empty": _format_concrete_expression_to_single_line, - "func_var_assigned": lambda e, ec, c: _append_to_expression_context_and_pass_standalone( - f"var {expression_to_str(e.children[0])} = ", e.children[1], ec, c - ), - "func_var_typed": _format_concrete_expression_to_single_line, - "func_var_typed_assgnd": lambda e, ec, c: _append_to_expression_context_and_pass_standalone( - f"var {expression_to_str(e.children[0])}: {expression_to_str(e.children[1])} = ", - e.children[2], - ec, - c, - ), - "func_var_inf": lambda e, ec, c: _append_to_expression_context_and_pass_standalone( - f"var {expression_to_str(e.children[0])} := ", e.children[1], ec, c - ), "dot_chain": _format_dot_chain_to_multiple_lines, "actual_getattr_call": _format_call_expression_to_multiple_lines, "actual_subscr_expr": _format_subscription_to_multiple_lines, @@ -645,100 +621,6 @@ def _format_annotation_to_multiple_lines( ) -def _format_inline_lambda_to_multiple_lines( - inline_lambda: Tree, - expression_context: ExpressionContext, - context: Context, -) -> FormattedLines: - expression_context_for_header = ExpressionContext( - expression_context.prefix_string, expression_context.prefix_line, "", -1 - ) - header_lines = _format_concrete_expression( - inline_lambda.children[0], expression_context_for_header, context - ) - last_header_line_number, last_header_line = header_lines[-1] - assert last_header_line_number is not None - expression_context_for_statements = ExpressionContext( - f"{last_header_line.strip()} ", - last_header_line_number, # type:ignore - expression_context.suffix_string, - expression_context.suffix_line, - ) - fake_meta = Meta() - fake_meta.line = get_line(inline_lambda.children[1]) - fake_meta.end_line = get_end_line(inline_lambda.children[-1]) - fake_expression = Tree( - "inline_lambda_statements", inline_lambda.children[1:], fake_meta - ) - statement_lines = _format_concrete_expression( - fake_expression, expression_context_for_statements, context - ) - return header_lines[:-1] + statement_lines - - -def _format_lambda_header_to_multiple_lines( - lambda_header: Tree, - expression_context: ExpressionContext, - context: Context, -) -> FormattedLines: - append_to_prefix = ( - f"func {lambda_header.children[0].value}" - if isinstance(lambda_header.children[0], Token) - else "func" - ) - args_offset = 1 if isinstance(lambda_header.children[0], Token) else 0 - theres_something_after_args = len(lambda_header.children) > args_offset + 1 - optional_type_hint = ( - f" -> {lambda_header.children[args_offset+1]}" - if theres_something_after_args - else "" - ) - prepend_to_suffix = f"{optional_type_hint}:" - new_expression_context = ExpressionContext( - f"{expression_context.prefix_string}{append_to_prefix}", - expression_context.prefix_line, - f"{prepend_to_suffix}{expression_context.suffix_string}", - expression_context.suffix_line, - ) - return _format_concrete_expression( - lambda_header.children[args_offset], new_expression_context, context - ) - - -def _format_inline_lambda_statements_to_multiple_lines( - inline_lambda_statements: Tree, - expression_context: ExpressionContext, - context: Context, -) -> FormattedLines: - lambda_statements = inline_lambda_statements.children - if len(lambda_statements) == 1: - return _format_concrete_expression( - lambda_statements[0], expression_context, context - ) - expression_context_for_first_statement = ExpressionContext( - expression_context.prefix_string, expression_context.prefix_line, "", -1 - ) - first_statement_formatted_lines = _format_concrete_expression( - lambda_statements[0], expression_context_for_first_statement, context - ) - last_line_number, last_line = first_statement_formatted_lines[-1] - assert last_line_number is not None - remaining_statements_prefix = last_line.strip() - remaining_statements_expression_context = ExpressionContext( - f"{remaining_statements_prefix} ; ", - last_line_number, # type: ignore - expression_context.suffix_string, - expression_context.suffix_line, - ) - fake_meta = Meta() - fake_meta.line = get_line(lambda_statements[1]) - fake_meta.end_line = get_end_line(lambda_statements[-1]) - fake_expression = Tree("inline_lambda_statements", lambda_statements[1:], fake_meta) - return first_statement_formatted_lines[:-1] + _format_concrete_expression( - fake_expression, remaining_statements_expression_context, context - ) - - def _collapse_getattr_tree_to_dot_chain(expression: Tree) -> Tree: reversed_dot_chain_children = [] # type: List[Node] pending_getattr_call_to_match = None @@ -883,3 +765,66 @@ def _format_dot_chain_to_multiple_lines_bottom_up( fake_meta, ) return _format_concrete_expression(new_actual_expr, expression_context, context) + + +def _format_lambda_to_multiple_lines( + a_lambda: Tree, + expression_context: ExpressionContext, + context: Context, +) -> FormattedLines: + expression_context_for_header = ExpressionContext( + expression_context.prefix_string, expression_context.prefix_line, "", -1 + ) + header_lines = _format_concrete_expression( + a_lambda.children[0], expression_context_for_header, context + ) + + block_module = import_module("gdtoolkit.formatter.block") + function_statement_module = import_module("gdtoolkit.formatter.function_statement") + child_context = context.create_child_context(expression_context.prefix_line) + (block_lines, _) = block_module.format_block( + a_lambda.children[1:], + function_statement_module.format_func_statement, + child_context, + ) + last_block_line_number, last_block_line_content = block_lines[-1] + + return ( + header_lines + + block_lines[:-1] + + [ + ( + last_block_line_number, + f"{last_block_line_content}{expression_context.suffix_string}", + ) + ] + ) + + +def _format_lambda_header_to_multiple_lines( + lambda_header: Tree, + expression_context: ExpressionContext, + context: Context, +) -> FormattedLines: + append_to_prefix = ( + f"func {lambda_header.children[0].value}" + if isinstance(lambda_header.children[0], Token) + else "func" + ) + args_offset = 1 if isinstance(lambda_header.children[0], Token) else 0 + theres_something_after_args = len(lambda_header.children) > args_offset + 1 + optional_type_hint = ( + f" -> {lambda_header.children[args_offset+1]}" + if theres_something_after_args + else "" + ) + prepend_to_suffix = f"{optional_type_hint}:" + new_expression_context = ExpressionContext( + f"{expression_context.prefix_string}{append_to_prefix}", + expression_context.prefix_line, + f"{prepend_to_suffix}{expression_context.suffix_string}", + expression_context.suffix_line, + ) + return _format_concrete_expression( + lambda_header.children[args_offset], new_expression_context, context + ) diff --git a/gdtoolkit/formatter/expression_to_str.py b/gdtoolkit/formatter/expression_to_str.py index 82c0a2ec..e0789a96 100644 --- a/gdtoolkit/formatter/expression_to_str.py +++ b/gdtoolkit/formatter/expression_to_str.py @@ -9,6 +9,7 @@ remove_outer_parentheses, has_trailing_comma, ) +from .function_statement_to_str import function_statement_to_str def standalone_expression_to_str(expression: Node) -> str: @@ -87,6 +88,8 @@ def expression_to_str(expression: Node) -> str: [expression_to_str(n) for n in e.children] ), "string_name": lambda e: f"&{expression_to_str(e.children[0])}", + "lambda": _lambda_to_str, + "lambda_header": _lambda_header_to_str, # fake expressions: "func_args": _args_to_str, "func_arg_regular": lambda e: "{}{}".format( @@ -121,30 +124,6 @@ def expression_to_str(expression: Node) -> str: "trailing_comma": lambda _: "", "annotation": _annotation_to_str, "annotation_args": _annotation_args_to_str, - "inline_lambda": _inline_lambda_to_str, - "lambda_header": _lambda_header_to_str, - "inline_lambda_statements": lambda e: " ; ".join( - expression_to_str(statement) for statement in e.children - ), - "pass_stmt": lambda _: "pass", - "return_stmt": lambda e: f"return {standalone_expression_to_str(e.children[0])}", - "expr_stmt": lambda e: f"{standalone_expression_to_str(e.children[0])}", - "func_var_stmt": lambda e: expression_to_str(e.children[0]), - "func_var_empty": lambda e: f"var {e.children[0].value}", - "func_var_assigned": lambda e: "var {} = {}".format( - e.children[0].value, standalone_expression_to_str(e.children[1]) - ), - "func_var_inf": lambda e: "var {} := {}".format( - e.children[0].value, standalone_expression_to_str(e.children[1]) - ), - "func_var_typed": lambda e: "var {}: {}".format( - e.children[0].value, standalone_expression_to_str(e.children[1]) - ), - "func_var_typed_assgnd": lambda e: "var {}: {} = {}".format( - e.children[0].value, - e.children[1].value, - standalone_expression_to_str(e.children[2]), - ), "non_foldable_dot_chain": lambda e: "".join(map(expression_to_str, e.children)), "actual_getattr_call": _getattr_call_to_str, "actual_subscr_expr": _subscription_to_str, @@ -242,10 +221,11 @@ def _annotation_args_to_str(annotation: Tree) -> str: return "({}{})".format(", ".join(elements), trailing_comma) -def _inline_lambda_to_str(inline_lambda: Tree) -> str: - fake_expression = Tree("inline_lambda_statements", inline_lambda.children[1:]) +def _lambda_to_str(a_lambda: Tree) -> str: + assert len(a_lambda.children) == 2 return "{} {}".format( - expression_to_str(inline_lambda.children[0]), expression_to_str(fake_expression) + expression_to_str(a_lambda.children[0]), + function_statement_to_str(a_lambda.children[1]), ) diff --git a/gdtoolkit/formatter/expression_utils.py b/gdtoolkit/formatter/expression_utils.py index b147ad84..2ff4e53e 100644 --- a/gdtoolkit/formatter/expression_utils.py +++ b/gdtoolkit/formatter/expression_utils.py @@ -47,13 +47,15 @@ def is_trailing_comma(expression: Node) -> bool: def is_expression_forcing_multiple_lines( expression: Node, standalone_comments: List[Optional[str]] ) -> bool: - if has_trailing_comma(expression): - return True - if _is_multiline_string(expression): + if has_trailing_comma(expression) or _is_multiline_string(expression): return True if isinstance(expression, Token): return False - if _has_standalone_comments(expression, standalone_comments): + if ( + _has_standalone_comments(expression, standalone_comments) + or _is_multistatement_lambda(expression) + or _is_unistatement_lambda_with_compoud_statement(expression) + ): return True for child in expression.children: if is_expression_forcing_multiple_lines(child, standalone_comments): @@ -82,10 +84,30 @@ def _is_multiline_string(expression: Node) -> bool: def _has_standalone_comments( expression: Tree, standalone_comments: List[Optional[str]] -): +) -> bool: return any( comment is not None for comment in standalone_comments[ get_line(expression) : get_end_line(expression) ] ) + + +def _is_multistatement_lambda(expression: Tree) -> bool: + return ( + isinstance(expression, Tree) + and expression.data == "lambda" + and len(expression.children) > 2 + ) + + +# TODO: remove once such statements are supported +def _is_unistatement_lambda_with_compoud_statement(expression: Tree) -> bool: + return ( + isinstance(expression, Tree) + and expression.data == "lambda" + and len(expression.children) == 2 + and isinstance(expression.children[1], Tree) + and expression.children[1].data + in ["if_stmt", "while_stmt", "for_stmt", "for_stmt_typed", "match_stmt"] + ) diff --git a/gdtoolkit/formatter/function_statement_to_str.py b/gdtoolkit/formatter/function_statement_to_str.py new file mode 100644 index 00000000..b9cec7d5 --- /dev/null +++ b/gdtoolkit/formatter/function_statement_to_str.py @@ -0,0 +1,58 @@ +from importlib import import_module + +from lark import Tree + + +def function_statement_to_str(statement: Tree) -> str: + expression_to_str_module = import_module("gdtoolkit.formatter.expression_to_str") + expression_to_str = expression_to_str_module.expression_to_str + standalone_expression_to_str = expression_to_str_module.standalone_expression_to_str + return { + "pass_stmt": lambda _: "pass", + "func_var_stmt": lambda s: function_statement_to_str(s.children[0]), + "const_stmt": lambda s: function_statement_to_str(s.children[0]), + "expr_stmt": lambda s: expression_to_str(s.children[0]), # TODO: standalone? + "return_stmt": lambda s: f"return {standalone_expression_to_str(s.children[0])}", + "break_stmt": _not_implemented, + "breakpoint_stmt": lambda _: "breakpoint", + "continue_stmt": _not_implemented, + "if_stmt": _not_implemented, + "while_stmt": _not_implemented, + "for_stmt": _not_implemented, + "for_stmt_typed": _not_implemented, + "match_stmt": _not_implemented, + "annotation": _not_implemented, + # statement fragments: + "func_var_empty": lambda s: f"var {s.children[0].value}", + "func_var_assigned": lambda s: "var {} = {}".format( + s.children[0].value, standalone_expression_to_str(s.children[1]) + ), + "func_var_inf": lambda s: "var {} := {}".format( + s.children[0].value, standalone_expression_to_str(s.children[1]) + ), + "func_var_typed": lambda s: "var {}: {}".format( + s.children[0].value, standalone_expression_to_str(s.children[1]) + ), + "func_var_typed_assgnd": lambda s: "var {}: {} = {}".format( + s.children[0].value, + s.children[1].value, + standalone_expression_to_str(s.children[2]), + ), + "const_assigned": lambda s: "const {} = {}".format( + s.children[0].value, standalone_expression_to_str(s.children[1]) + ), + "const_typed_assigned": lambda s: "const {}: {} = {}".format( + s.children[0].value, + s.children[1].value, + standalone_expression_to_str(s.children[2]), + ), + "const_inf": lambda s: "const {} := {}".format( + s.children[0].value, standalone_expression_to_str(s.children[1]) + ), + "match_branch": _not_implemented, + "guarded_match_branch": _not_implemented, + }[statement.data](statement) + + +def _not_implemented(statement: Tree) -> str: + raise NotImplementedError diff --git a/gdtoolkit/parser/gdscript.lark b/gdtoolkit/parser/gdscript.lark index 33302567..26bbad32 100644 --- a/gdtoolkit/parser/gdscript.lark +++ b/gdtoolkit/parser/gdscript.lark @@ -79,7 +79,7 @@ func_args: "(" [func_arg ("," func_arg)* [trailing_comma]] ")" func_arg_regular: NAME ["=" expr] func_arg_inf: NAME ":" "=" expr func_arg_typed: NAME ":" TYPE_HINT ["=" expr] -_func_suite: _func_body +_func_suite: _func_body _NL | _func_stmt _func_body: _NL _INDENT (_func_stmt+ | _func_stmt* (_simple_func_stmt | annotation+)) _DEDENT _func_stmt: _simple_func_stmt _NL @@ -244,15 +244,29 @@ _plus_atom: ["+"] atom | NAME | HEX | BIN - | inline_lambda + | lambda | literal -inline_lambda: lambda_header _simple_lambda_stmt +lambda: lambda_header _lambda_suite lambda_header: "func" [NAME] func_args ["->" TYPE_HINT] ":" -_simple_lambda_stmt: single_lambda_stmt (";" single_lambda_stmt)* [";"] -?single_lambda_stmt: pass_stmt - | return_stmt - | func_var_stmt - | expr_stmt +// the only difference between _lambda_suite and _func_suite is that +// _lambda_suite never consumes last _NL (after stmt or _DEDENT) +// as the last _NL in every lambda case belongs to parent stmt +_lambda_suite: _lambda_body + | _standalone_lambda_stmt +_lambda_body: _NL _INDENT _func_stmt+ _DEDENT +_standalone_lambda_stmt: _simple_func_stmt + // | annotation* compound_lambda_stmt + // | annotation* compound_func_stmt + | annotation* +// ?compound_lambda_stmt: lambda_if_stmt + // | while_stmt + // | for_stmt + // | for_stmt_typed + // | match_stmt +// lambda_if_stmt: lambda_if_branch (_NL? lambda_elif_branch)* [_NL? lambda_else_branch] +// lambda_if_branch: "if" expr ":" _lambda_suite +// lambda_elif_branch: "elif" expr ":" _lambda_suite +// lambda_else_branch: "else" ":" _lambda_suite ?literal: NUMBER | string | rstring diff --git a/gdtoolkit/parser/gdscript_indenter.py b/gdtoolkit/parser/gdscript_indenter.py new file mode 100644 index 00000000..5ce8d416 --- /dev/null +++ b/gdtoolkit/parser/gdscript_indenter.py @@ -0,0 +1,133 @@ +from typing import Iterator +from collections import defaultdict + +from lark.indenter import DedentError, Indenter +from lark.lexer import Token + + +class GDScriptIndenter(Indenter): + NL_type = "_NL" + OPEN_PAREN_types = ["LPAR", "LSQB", "LBRACE"] + CLOSE_PAREN_types = ["RPAR", "RSQB", "RBRACE"] + LAMBDA_SEPARATOR_types = ["COMMA"] + INDENT_type = "_INDENT" + DEDENT_type = "_DEDENT" + # TODO: guess tab length + tab_len = 4 + + def __init__(self): + super().__init__() + self.processed_tokens = [] + self.undedented_lambdas_at_paren_level = defaultdict(int) + + def handle_NL(self, token: Token) -> Iterator[Token]: + indent_str = token.rsplit("\n", 1)[1] # Tabs and spaces + indent = indent_str.count(" ") + indent_str.count("\t") * self.tab_len + + if self.paren_level > 0: + for new_token in self._handle_lambdas_on_newline_token_in_parens( + token, indent, indent_str + ): + yield new_token + # special handling for lambdas + return + + yield token + + if indent > self.indent_level[-1]: + self.indent_level.append(indent) + yield Token.new_borrow_pos(self.INDENT_type, indent_str, token) + else: + while indent < self.indent_level[-1]: + self.indent_level.pop() + yield Token( + self.DEDENT_type, indent_str, None, token.line, None, token.line + ) + # produce extra newline after dedent to simplify grammar: + yield token + + if indent != self.indent_level[-1]: + raise DedentError( + "Unexpected dedent to column %s. Expected dedent to %s" + % (indent, self.indent_level[-1]) + ) + + def _process(self, stream): + self.processed_tokens = [] + self.undedented_lambdas_at_paren_level = defaultdict(int) + for token in stream: + self.processed_tokens.append(token) + if token.type == self.NL_type: + yield from self.handle_NL(token) + + if token.type in self.OPEN_PAREN_types: + self.paren_level += 1 + elif token.type in self.CLOSE_PAREN_types: + while self.undedented_lambdas_at_paren_level[self.paren_level] > 0: + for new_token in self._dedent_lambda_at_token(token): + yield new_token + self.paren_level -= 1 + assert self.paren_level >= 0 + elif token.type in self.LAMBDA_SEPARATOR_types: + if self.undedented_lambdas_at_paren_level[self.paren_level] > 0: + for new_token in self._dedent_lambda_at_token(token): + yield new_token + + if token.type != self.NL_type: + yield token + + while len(self.indent_level) > 1: + self.indent_level.pop() + yield Token(self.DEDENT_type, "") + + assert self.indent_level == [0], self.indent_level + + def _handle_lambdas_on_newline_token_in_parens( + self, token: Token, indent: int, indent_str: str + ): + if ( + self._current_token_is_just_after_lambda_header() + and indent > self.indent_level[-1] + ): + self.indent_level.append(indent) + self.undedented_lambdas_at_paren_level[self.paren_level] += 1 + yield token + yield Token.new_borrow_pos(self.INDENT_type, indent_str, token) + elif ( + indent <= self.indent_level[-1] + and self.undedented_lambdas_at_paren_level[self.paren_level] > 0 + ): + yield token + + while indent < self.indent_level[-1]: + self.indent_level.pop() + self.undedented_lambdas_at_paren_level[self.paren_level] -= 1 + yield Token.new_borrow_pos(self.DEDENT_type, indent_str, token) + + if indent != self.indent_level[-1]: + raise DedentError( + "Unexpected dedent to column %s. Expected dedent to %s" + % (indent, self.indent_level[-1]) + ) + + def _dedent_lambda_at_token(self, token: Token): + self.indent_level.pop() + self.undedented_lambdas_at_paren_level[self.paren_level] -= 1 + yield Token.new_borrow_pos(self.NL_type, "N/A", token) + yield Token.new_borrow_pos(self.DEDENT_type, "N/A", token) + + def _current_token_is_just_after_lambda_header(self): + # TODO: handle newlines etc. in between tokens + return ( + len(self.processed_tokens) > 0 + and self.processed_tokens[-2].type == "COLON" + and self.processed_tokens[-3].type == "RPAR" + and self.processed_tokens[-4].type == "LPAR" + and ( + self.processed_tokens[-5].type == "FUNC" + or ( + self.processed_tokens[-5].type == "NAME" + and self.processed_tokens[-6].type == "FUNC" + ) + ) + ) diff --git a/gdtoolkit/parser/parser.py b/gdtoolkit/parser/parser.py index 71cef1ff..be0545e9 100644 --- a/gdtoolkit/parser/parser.py +++ b/gdtoolkit/parser/parser.py @@ -7,17 +7,9 @@ import sys import pkg_resources -from lark import Lark, Tree, indenter +from lark import Lark, Tree - -class Indenter(indenter.Indenter): - NL_type = "_NL" - OPEN_PAREN_types = ["LPAR", "LSQB", "LBRACE"] - CLOSE_PAREN_types = ["RPAR", "RSQB", "RBRACE"] - INDENT_type = "_INDENT" - DEDENT_type = "_DEDENT" - # TODO: guess tab length - tab_len = 4 +from .gdscript_indenter import GDScriptIndenter # TODO: when upgrading to Python 3.8, replace with functools.cached_property @@ -92,7 +84,7 @@ def _get_parser( grammar_filepath, parser="lalr", start="start", - postlex=Indenter(), # type: ignore + postlex=GDScriptIndenter(), # type: ignore propagate_positions=add_metadata, maybe_placeholders=False, cache=cache_filepath, diff --git a/tests/conftest.py b/tests/conftest.py index 0d5f4361..85a26767 100644 --- a/tests/conftest.py +++ b/tests/conftest.py @@ -10,6 +10,7 @@ def pytest_configure(config): config.addinivalue_line( "markers", "generated: testcases w/ content generated by hypothesis" ) + config.addinivalue_line("markers", "parser: parser testcases") @pytest.fixture(scope="session", autouse=True) diff --git a/tests/formatter/input-output-pairs/complex_multistatement_lambdas.in.gd b/tests/formatter/input-output-pairs/complex_multistatement_lambdas.in.gd new file mode 100644 index 00000000..4f9490b9 --- /dev/null +++ b/tests/formatter/input-output-pairs/complex_multistatement_lambdas.in.gd @@ -0,0 +1,221 @@ +func foo(x): + pass +func bar(x,y): + pass +func actual_params(): + foo(func(): + var x = 1 + return x) + + foo(func(): + var x = 1 + if x > 1: + print(x)) + + foo(func(): + var x = 1 + if x > 1: + print(x) + ) + + bar(func(): + var x = 1 + return x, func(): + var y = 1 + return y) + + bar(func(): + var x = 1 + return x, + func(): + var y = 1 + return y) + + bar(func(): + var x = 1 + return x, + + func(): + var y = 1 + return y) + + bar(func(): + var x = 1 + if x > 0: + print(x), func(): + var y = 1 + return y) + + bar(func(): + var x = 1 + if x > 0: + print(x), + func(): + var y = 1 + return y) + +func arrays(): + var x1 = [func(): + var x = 1 + return x] + var x2 = [func(): + var x = 1 + return x + ] + var x3 = [func(): + var x = 1 + return x,func(): + var x = 1 + return x + ] + var x4 = [func(): + var x = 1 + return x, + func(): + var x = 1 + return x + ] + var x5 = [func(): + var x = 1 + return x, + + func(): + var x = 1 + return x + ] + var x6 = [func(): + var x = 1 + if x > 0: + print(x), + func(): + var x = 1 + return x + ] + var x7 = [func(): + var x = 1 + if x > 0: + print(x), + + func(): + var x = 1 + return x + ] + +func dicts(): + var x1 = {'a':func(): + var x = 1 + return x} + var x2 = {'a':func(): + var x = 1 + return x + } + var x3 = {'a':func(): + var x = 1 + return x,'b':func(): + var x = 1 + return x + } + var x4 = {'a':func(): + var x = 1 + return x, + 'b':func(): + var x = 1 + return x + } + var x5 = {'a':func(): + var x = 1 + return x,'b': + func(): + var x = 1 + return x + } + var x6 = {'a':func(): + var x = 1 + return x, + + 'b':func(): + var x = 1 + return x + } + var x7 = {'a':func(): + var x = 1 + if x > 0: + print(x),'b':func(): + var x = 1 + return x + } + var x8 = {'a':func(): + var x = 1 + if x > 0: + print(x), + 'b':func(): + var x = 1 + return x + } + var x9 = {'a':func(): + var x = 1 + if x > 0: + print(x), + + 'b':func(): + var x = 1 + return x + } + +func nested(): + var x1 = func(): + var x1r = func(): + var x = 1 + return x + return x1r + + var x2 = func(): + var x2r = func(): + pass + pass + pass + + var x3 = func(): + var x3r = func(): + var x3rr = func(): + pass + pass + pass + pass + + var x4 = func(): + if true: + var x4r = func(): + pass + pass + pass + pass + + var x5 = func(): + if true: + var x5r = func(): + if true: + pass + pass + pass + pass + pass + + var x6 = func(): + if true: + var x6r = func(): + if true: + var x6rr = func(): + pass + pass + pass + pass + pass + pass + + # TODO: fix + # var x7 = [func(): + # pass + # var x = func(): + # pass + # pass,] diff --git a/tests/formatter/input-output-pairs/complex_multistatement_lambdas.out.gd b/tests/formatter/input-output-pairs/complex_multistatement_lambdas.out.gd new file mode 100644 index 00000000..324f52ed --- /dev/null +++ b/tests/formatter/input-output-pairs/complex_multistatement_lambdas.out.gd @@ -0,0 +1,277 @@ +func foo(x): + pass + + +func bar(x, y): + pass + + +func actual_params(): + foo( + func(): + var x = 1 + return x + ) + + foo( + func(): + var x = 1 + if x > 1: + print(x) + ) + + foo( + func(): + var x = 1 + if x > 1: + print(x) + ) + + bar( + func(): + var x = 1 + return x, + func(): + var y = 1 + return y + ) + + bar( + func(): + var x = 1 + return x, + func(): + var y = 1 + return y + ) + + bar( + func(): + var x = 1 + return x, + func(): + var y = 1 + return y + ) + + bar( + func(): + var x = 1 + if x > 0: + print(x), + func(): + var y = 1 + return y + ) + + bar( + func(): + var x = 1 + if x > 0: + print(x), + func(): + var y = 1 + return y + ) + + +func arrays(): + var x1 = [ + func(): + var x = 1 + return x + ] + var x2 = [ + func(): + var x = 1 + return x + ] + var x3 = [ + func(): + var x = 1 + return x, + func(): + var x = 1 + return x + ] + var x4 = [ + func(): + var x = 1 + return x, + func(): + var x = 1 + return x + ] + var x5 = [ + func(): + var x = 1 + return x, + func(): + var x = 1 + return x + ] + var x6 = [ + func(): + var x = 1 + if x > 0: + print(x), + func(): + var x = 1 + return x + ] + var x7 = [ + func(): + var x = 1 + if x > 0: + print(x), + func(): + var x = 1 + return x + ] + + +func dicts(): + var x1 = { + "a": + func(): + var x = 1 + return x + } + var x2 = { + "a": + func(): + var x = 1 + return x + } + var x3 = { + "a": + func(): + var x = 1 + return x, + "b": + func(): + var x = 1 + return x + } + var x4 = { + "a": + func(): + var x = 1 + return x, + "b": + func(): + var x = 1 + return x + } + var x5 = { + "a": + func(): + var x = 1 + return x, + "b": + func(): + var x = 1 + return x + } + var x6 = { + "a": + func(): + var x = 1 + return x, + "b": + func(): + var x = 1 + return x + } + var x7 = { + "a": + func(): + var x = 1 + if x > 0: + print(x), + "b": + func(): + var x = 1 + return x + } + var x8 = { + "a": + func(): + var x = 1 + if x > 0: + print(x), + "b": + func(): + var x = 1 + return x + } + var x9 = { + "a": + func(): + var x = 1 + if x > 0: + print(x), + "b": + func(): + var x = 1 + return x + } + + +func nested(): + var x1 = func(): + var x1r = func(): + var x = 1 + return x + return x1r + + var x2 = func(): + var x2r = func(): + pass + pass + pass + + var x3 = func(): + var x3r = func(): + var x3rr = func(): + pass + pass + pass + pass + + var x4 = func(): + if true: + var x4r = func(): + pass + pass + pass + pass + + var x5 = func(): + if true: + var x5r = func(): + if true: + pass + pass + pass + pass + pass + + var x6 = func(): + if true: + var x6r = func(): + if true: + var x6rr = func(): + pass + pass + pass + pass + pass + pass + + # TODO: fix + # var x7 = [func(): + # pass + # var x = func(): + # pass + # pass,] diff --git a/tests/formatter/input-output-pairs/complex_unistatement_lambdas.in.gd b/tests/formatter/input-output-pairs/complex_unistatement_lambdas.in.gd new file mode 100644 index 00000000..a0c1accc --- /dev/null +++ b/tests/formatter/input-output-pairs/complex_unistatement_lambdas.in.gd @@ -0,0 +1,12 @@ +func foo(x): + pass +func bar(x,y): + pass + +func baz(): + foo(func(): pass) + bar(func(): pass,func(): pass) + var x1 = [func(): pass,func(): pass] + var x2 = [func(): pass,func():pass,] + var x3 = {'x':func(): pass,'y':func(): pass} + var x4 = {'x':func(): pass,'y':func(): pass,} diff --git a/tests/formatter/input-output-pairs/complex_unistatement_lambdas.out.gd b/tests/formatter/input-output-pairs/complex_unistatement_lambdas.out.gd new file mode 100644 index 00000000..5268cf78 --- /dev/null +++ b/tests/formatter/input-output-pairs/complex_unistatement_lambdas.out.gd @@ -0,0 +1,21 @@ +func foo(x): + pass + + +func bar(x, y): + pass + + +func baz(): + foo(func(): pass) + bar(func(): pass, func(): pass) + var x1 = [func(): pass, func(): pass] + var x2 = [ + func(): pass, + func(): pass, + ] + var x3 = {"x": func(): pass, "y": func(): pass} + var x4 = { + "x": func(): pass, + "y": func(): pass, + } diff --git a/tests/formatter/input-output-pairs/inline_lambdas_w_comments.out.gd b/tests/formatter/input-output-pairs/inline_lambdas_w_comments.out.gd index c62349d6..fdf9a41a 100644 --- a/tests/formatter/input-output-pairs/inline_lambdas_w_comments.out.gd +++ b/tests/formatter/input-output-pairs/inline_lambdas_w_comments.out.gd @@ -26,7 +26,8 @@ func foo(): p21, p22, p23 - ): pass # inline b + ): + pass # inline b # c var x3 = func baz( # inline c # d @@ -55,48 +56,52 @@ func foo(): p22, p23 # inline e # f - ) -> int: pass ; pass ; var x := [ # inline f - # g - 0, # inline g - # h - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 # inline h - # i - ] ; pass # inline i + ) -> int: + pass + pass + var x := [ # inline f + # g + 0, # inline g + # h + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 # inline h + # i + ] + pass # inline i # j diff --git a/tests/formatter/input-output-pairs/long_inline_lambdas.in.gd b/tests/formatter/input-output-pairs/long_inline_lambdas.in.gd deleted file mode 100644 index 972ff78b..00000000 --- a/tests/formatter/input-output-pairs/long_inline_lambdas.in.gd +++ /dev/null @@ -1,16 +0,0 @@ -func xyz(x): - pass -func foo(): - var x1 = func(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): pass - var x2 = func(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: pass - var x3 = func bar(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): pass - var x4 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: pass - - var x5 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: pass;pass;return 123 - var x6 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: pass;pass;return [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];pass - var x7 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: pass;pass;xyz([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]);pass - var x8 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: pass;pass;var xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx;pass - var x9 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: pass;pass;var x=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];pass - var x10 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: pass;pass;var xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:int;pass - var x11 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: pass;pass;var x:Array=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];pass - var x12 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: pass;pass;var x:=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0];pass diff --git a/tests/formatter/input-output-pairs/long_multistatement_lambdas.in.gd b/tests/formatter/input-output-pairs/long_multistatement_lambdas.in.gd new file mode 100644 index 00000000..bf65310e --- /dev/null +++ b/tests/formatter/input-output-pairs/long_multistatement_lambdas.in.gd @@ -0,0 +1,16 @@ +func xyz(x): + pass +func foo(): + var x1 = func(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: + var a = [1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1] + var b = len(a) + 1 + if a > 1: + return 1 + return 2 + var x2 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): + var a = {'a1':1,'a2':1,'a3':1,'a4':1,'a5':1,'a6':1,'a7':1,'a8':1,'a9':1,'a10':1,'a11':1,'a12':1,'a13':1,'a14':1,'a15':1,'a16':1,'a17':1} + var b = [a['a1'],1,2,3] + for bb in b: + break + + pass diff --git a/tests/formatter/input-output-pairs/long_multistatement_lambdas.out.gd b/tests/formatter/input-output-pairs/long_multistatement_lambdas.out.gd new file mode 100644 index 00000000..934fe597 --- /dev/null +++ b/tests/formatter/input-output-pairs/long_multistatement_lambdas.out.gd @@ -0,0 +1,133 @@ +func xyz(x): + pass + + +func foo(): + var x1 = func( + p1, + p2, + p3, + p4, + p5, + p6, + p7, + p8, + p9, + p10, + p11, + p12, + p13, + p14, + p15, + p16, + p17, + p18, + p19, + p20, + p21, + p22, + p23 + ) -> int: + var a = [ + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1, + 1 + ] + var b = len(a) + 1 + if a > 1: + return 1 + return 2 + var x2 = func baz( + p1, + p2, + p3, + p4, + p5, + p6, + p7, + p8, + p9, + p10, + p11, + p12, + p13, + p14, + p15, + p16, + p17, + p18, + p19, + p20, + p21, + p22, + p23 + ): + var a = { + "a1": 1, + "a2": 1, + "a3": 1, + "a4": 1, + "a5": 1, + "a6": 1, + "a7": 1, + "a8": 1, + "a9": 1, + "a10": 1, + "a11": 1, + "a12": 1, + "a13": 1, + "a14": 1, + "a15": 1, + "a16": 1, + "a17": 1 + } + var b = [a["a1"], 1, 2, 3] + for bb in b: + break + + pass diff --git a/tests/formatter/input-output-pairs/long_unistatement_lambdas.in.gd b/tests/formatter/input-output-pairs/long_unistatement_lambdas.in.gd new file mode 100644 index 00000000..821021d5 --- /dev/null +++ b/tests/formatter/input-output-pairs/long_unistatement_lambdas.in.gd @@ -0,0 +1,15 @@ +func xyz(x): + pass +func foo(): + var x1 = func(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): pass + var x2 = func(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: return 1 + var x3 = func bar(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): pass + var x4 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23) -> int: return 1 + + var x5 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): return [0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] + var x6 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): xyz([0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]) + var x8 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): var xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx + var x9 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): var x=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] + var x10 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): var xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx:int + var x11 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): var x:Array=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] + var x12 = func baz(p1,p2,p3,p4,p5,p6,p7,p8,p9,p10,p11,p12,p13,p14,p15,p16,p17,p18,p19,p20,p21,p22,p23): var x:=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0] diff --git a/tests/formatter/input-output-pairs/long_inline_lambdas.out.gd b/tests/formatter/input-output-pairs/long_unistatement_lambdas.out.gd similarity index 58% rename from tests/formatter/input-output-pairs/long_inline_lambdas.out.gd rename to tests/formatter/input-output-pairs/long_unistatement_lambdas.out.gd index bc188974..b5f920c8 100644 --- a/tests/formatter/input-output-pairs/long_inline_lambdas.out.gd +++ b/tests/formatter/input-output-pairs/long_unistatement_lambdas.out.gd @@ -27,7 +27,8 @@ func foo(): p21, p22, p23 - ): pass + ): + pass var x2 = func( p1, p2, @@ -52,7 +53,8 @@ func foo(): p21, p22, p23 - ) -> int: pass + ) -> int: + return 1 var x3 = func bar( p1, p2, @@ -77,7 +79,8 @@ func foo(): p21, p22, p23 - ): pass + ): + pass var x4 = func baz( p1, p2, @@ -102,7 +105,8 @@ func foo(): p21, p22, p23 - ) -> int: pass + ) -> int: + return 1 var x5 = func baz( p1, @@ -128,98 +132,8 @@ func foo(): p21, p22, p23 - ) -> int: pass ; pass ; return 123 - var x6 = func baz( - p1, - p2, - p3, - p4, - p5, - p6, - p7, - p8, - p9, - p10, - p11, - p12, - p13, - p14, - p15, - p16, - p17, - p18, - p19, - p20, - p21, - p22, - p23 - ) -> int: pass ; pass ; return [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ] ; pass - var x7 = func baz( - p1, - p2, - p3, - p4, - p5, - p6, - p7, - p8, - p9, - p10, - p11, - p12, - p13, - p14, - p15, - p16, - p17, - p18, - p19, - p20, - p21, - p22, - p23 - ) -> int: pass ; pass ; xyz( - [ + ): + return [ 0, 0, 0, @@ -260,7 +174,74 @@ func foo(): 0, 0 ] - ) ; pass + var x6 = func baz( + p1, + p2, + p3, + p4, + p5, + p6, + p7, + p8, + p9, + p10, + p11, + p12, + p13, + p14, + p15, + p16, + p17, + p18, + p19, + p20, + p21, + p22, + p23 + ): + xyz( + [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] + ) var x8 = func baz( p1, p2, @@ -285,7 +266,8 @@ func foo(): p21, p22, p23 - ) -> int: pass ; pass ; var xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx ; pass + ): + var xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx var x9 = func baz( p1, p2, @@ -310,47 +292,48 @@ func foo(): p21, p22, p23 - ) -> int: pass ; pass ; var x = [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ] ; pass + ): + var x = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] var x10 = func baz( p1, p2, @@ -375,7 +358,8 @@ func foo(): p21, p22, p23 - ) -> int: pass ; pass ; var xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: int ; pass + ): + var xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: int var x11 = func baz( p1, p2, @@ -400,47 +384,48 @@ func foo(): p21, p22, p23 - ) -> int: pass ; pass ; var x: Array = [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ] ; pass + ): + var x: Array = [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] var x12 = func baz( p1, p2, @@ -465,44 +450,45 @@ func foo(): p21, p22, p23 - ) -> int: pass ; pass ; var x := [ - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0, - 0 - ] ; pass + ): + var x := [ + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0, + 0 + ] diff --git a/tests/formatter/input-output-pairs/simple_inline_lambdas.in.gd b/tests/formatter/input-output-pairs/simple_inline_lambdas.in.gd deleted file mode 100644 index 6e071d5d..00000000 --- a/tests/formatter/input-output-pairs/simple_inline_lambdas.in.gd +++ /dev/null @@ -1,12 +0,0 @@ -func foo(): - var x1 = func(): pass - var x2 = func(x): pass;pass - var x3 = func(x: int): return 123;pass - var x4 = func bar(): pass;123 - var x5 = func() -> int: 1 - var x6 = func baz() -> int: pass - var x7 = func(): var x - var x8 = func(): var x=1 - var x9 = func(): var x:int - var x10 = func(): var x:int=1 - var x11 = func(): var x:=1 diff --git a/tests/formatter/input-output-pairs/simple_inline_lambdas.out.gd b/tests/formatter/input-output-pairs/simple_inline_lambdas.out.gd deleted file mode 100644 index cafe457e..00000000 --- a/tests/formatter/input-output-pairs/simple_inline_lambdas.out.gd +++ /dev/null @@ -1,12 +0,0 @@ -func foo(): - var x1 = func(): pass - var x2 = func(x): pass ; pass - var x3 = func(x: int): return 123 ; pass - var x4 = func bar(): pass ; 123 - var x5 = func() -> int: 1 - var x6 = func baz() -> int: pass - var x7 = func(): var x - var x8 = func(): var x = 1 - var x9 = func(): var x: int - var x10 = func(): var x: int = 1 - var x11 = func(): var x := 1 diff --git a/tests/formatter/input-output-pairs/simple_multistatement_lambdas.in.gd b/tests/formatter/input-output-pairs/simple_multistatement_lambdas.in.gd new file mode 100644 index 00000000..604c3d94 --- /dev/null +++ b/tests/formatter/input-output-pairs/simple_multistatement_lambdas.in.gd @@ -0,0 +1,20 @@ +func foo(): + var x1 = func(x): pass;pass + var x2 = func(x: int): return 123;pass + var x3 = func bar(): pass;123 + +func baz(): + var x1 = func(x): + var y =x+1 + if y: + return 1 + return 2 + var x2 = func(): + if true: + var x=1 + if x>0: + return 5 + return 6 + return 7 + + pass diff --git a/tests/formatter/input-output-pairs/simple_multistatement_lambdas.out.gd b/tests/formatter/input-output-pairs/simple_multistatement_lambdas.out.gd new file mode 100644 index 00000000..584018a6 --- /dev/null +++ b/tests/formatter/input-output-pairs/simple_multistatement_lambdas.out.gd @@ -0,0 +1,27 @@ +func foo(): + var x1 = func(x): + pass + pass + var x2 = func(x: int): + return 123 + pass + var x3 = func bar(): + pass + 123 + + +func baz(): + var x1 = func(x): + var y = x + 1 + if y: + return 1 + return 2 + var x2 = func(): + if true: + var x = 1 + if x > 0: + return 5 + return 6 + return 7 + + pass diff --git a/tests/formatter/input-output-pairs/simple_unistatement_lambdas.in.gd b/tests/formatter/input-output-pairs/simple_unistatement_lambdas.in.gd new file mode 100644 index 00000000..a08d3621 --- /dev/null +++ b/tests/formatter/input-output-pairs/simple_unistatement_lambdas.in.gd @@ -0,0 +1,68 @@ +func foo(): + var x1 = func(): pass + var x2 = func() -> int: return 1 + var x3 = func baz() -> int: return 1 + var x5 = func(): 1 + var x6 = func baz(): pass + var x7 = func(): var x + var x8 = func(): var x=1 + var x9 = func(): var x:int + var x10 = func(): var x:int=1 + var x11 = func(): var x:=1 + var x12 = func(): breakpoint + var x13 = func(): const foo =1 + var x13a = func(): const foo:int =1 + var x13b = func(): const foo:=1 + # TODO: fix + # var x14 = func(): if true: pass + # var x15 = func(): while false: pass + # var x16 = func(): for x in [1]: pass + # var x17 = func(): for x : int in [1]: pass + pass + +func bar(): + var x1 = func(): + pass + var x2 = func() -> int: + return 1 + var x3 = func baz() -> int: + return 1 + var x5 = func(): + 1 + var x6 = func baz(): + pass + var x7 = func(): + var x + var x8 = func(): + var x=1 + var x9 = func(): + var x:int + var x10 = func(): + var x:int=1 + var x11 = func(): + var x:=1 + var x12 = func(): + breakpoint + var x13 = func(): + const foo =1 + var x13a = func(): + const foo:int =1 + var x13b = func(): + const foo:=1 + var x14 = func(): + if true: + pass + var x15 = func(): + while false: + pass + var x16 = func(): + for x in [1]: + pass + var x17 = func(): + for x : int in [1]: + pass + var x18 = func(): + match 1: + _: + pass + pass diff --git a/tests/formatter/input-output-pairs/simple_unistatement_lambdas.out.gd b/tests/formatter/input-output-pairs/simple_unistatement_lambdas.out.gd new file mode 100644 index 00000000..83e8e7ea --- /dev/null +++ b/tests/formatter/input-output-pairs/simple_unistatement_lambdas.out.gd @@ -0,0 +1,55 @@ +func foo(): + var x1 = func(): pass + var x2 = func() -> int: return 1 + var x3 = func baz() -> int: return 1 + var x5 = func(): 1 + var x6 = func baz(): pass + var x7 = func(): var x + var x8 = func(): var x = 1 + var x9 = func(): var x: int + var x10 = func(): var x: int = 1 + var x11 = func(): var x := 1 + var x12 = func(): breakpoint + var x13 = func(): const foo = 1 + var x13a = func(): const foo: int = 1 + var x13b = func(): const foo := 1 + # TODO: fix + # var x14 = func(): if true: pass + # var x15 = func(): while false: pass + # var x16 = func(): for x in [1]: pass + # var x17 = func(): for x : int in [1]: pass + pass + + +func bar(): + var x1 = func(): pass + var x2 = func() -> int: return 1 + var x3 = func baz() -> int: return 1 + var x5 = func(): 1 + var x6 = func baz(): pass + var x7 = func(): var x + var x8 = func(): var x = 1 + var x9 = func(): var x: int + var x10 = func(): var x: int = 1 + var x11 = func(): var x := 1 + var x12 = func(): breakpoint + var x13 = func(): const foo = 1 + var x13a = func(): const foo: int = 1 + var x13b = func(): const foo := 1 + var x14 = func(): + if true: + pass + var x15 = func(): + while false: + pass + var x16 = func(): + for x in [1]: + pass + var x17 = func(): + for x: int in [1]: + pass + var x18 = func(): + match 1: + _: + pass + pass diff --git a/tests/formatter/test_input_output_pairs.py b/tests/formatter/test_input_output_pairs.py index aa7886ef..235332af 100644 --- a/tests/formatter/test_input_output_pairs.py +++ b/tests/formatter/test_input_output_pairs.py @@ -5,7 +5,12 @@ DATA_DIR = "./input-output-pairs" -EXCEPTIONS = set([]) # type: Set[str] +EXCEPTIONS = set( + [ + # TODO: fix + "inline_lambdas_w_comments", + ] +) # type: Set[str] def pytest_generate_tests(metafunc): diff --git a/tests/formatter/test_scripts_validity.py b/tests/formatter/test_scripts_validity.py index fa58a6cc..e4efe1e0 100644 --- a/tests/formatter/test_scripts_validity.py +++ b/tests/formatter/test_scripts_validity.py @@ -11,8 +11,6 @@ EXCEPTIONS = set( [ # cases where Godot does more than just parsing - "simple_inline_lambdas.in.gd", - "simple_inline_lambdas.out.gd", "inline_lambdas_w_comments.in.gd", "inline_lambdas_w_comments.out.gd", "long_inline_lambdas.in.gd", diff --git a/tests/parser/test_godot_parser.py b/tests/parser/test_godot_parser.py new file mode 100644 index 00000000..9568818c --- /dev/null +++ b/tests/parser/test_godot_parser.py @@ -0,0 +1,74 @@ +import os +import subprocess +import shutil + +import pytest + +from ..common import GODOT_SERVER, write_project_settings, write_file + + +OK_DATA_DIR = "../valid-gd-scripts" +NOK_DATA_DIR = "../invalid-gd-scripts" +BUGS_DATA_DIR = "../potential-godot-bugs" + + +def pytest_generate_tests(metafunc): + this_directory = os.path.dirname(os.path.abspath(__file__)) + if "gdscript_ok_path" in metafunc.fixturenames: + directory_tests = os.path.join(this_directory, OK_DATA_DIR) + metafunc.parametrize( + "gdscript_ok_path", + [os.path.join(directory_tests, f) for f in os.listdir(directory_tests)], + ) + if "gdscript_nok_path" in metafunc.fixturenames: + directory_tests = os.path.join(this_directory, NOK_DATA_DIR) + metafunc.parametrize( + "gdscript_nok_path", + [os.path.join(directory_tests, f) for f in os.listdir(directory_tests)], + ) + if "gdscript_bug_path" in metafunc.fixturenames: + directory_tests = os.path.join(this_directory, BUGS_DATA_DIR) + metafunc.parametrize( + "gdscript_bug_path", + [os.path.join(directory_tests, f) for f in os.listdir(directory_tests)], + ) + + +@pytest.mark.skipif(shutil.which(GODOT_SERVER) is None, reason="requires godot server") +@pytest.mark.godot_check_only +def test_godot_check_only_success(gdscript_ok_path, tmp_path): + write_project_settings(tmp_path) + write_file(tmp_path, "dummy.gd", "class X:\n\tpass") + with subprocess.Popen( + [ + GODOT_SERVER, + "--headless", + "--check-only", + "-s", + gdscript_ok_path, + "--path", + tmp_path, + ], + ) as process: + process.wait() + assert process.returncode == 0 + + +@pytest.mark.skipif(shutil.which(GODOT_SERVER) is None, reason="requires godot server") +@pytest.mark.godot_check_only +def test_godot_check_only_failure(gdscript_nok_path): + with subprocess.Popen( + [GODOT_SERVER, "--headless", "--check-only", "-s", gdscript_nok_path], + ) as process: + process.wait() + assert process.returncode != 0 + + +@pytest.mark.skipif(shutil.which(GODOT_SERVER) is None, reason="requires godot server") +@pytest.mark.godot_check_only +def test_godot_check_only_potential_bugs(gdscript_bug_path): + with subprocess.Popen( + [GODOT_SERVER, "--headless", "--check-only", "-s", gdscript_bug_path], + ) as process: + process.wait() + assert process.returncode != 0 diff --git a/tests/parser/test_parser.py b/tests/parser/test_parser.py index f9b499ff..888890a3 100644 --- a/tests/parser/test_parser.py +++ b/tests/parser/test_parser.py @@ -1,66 +1,42 @@ import os -import subprocess -import shutil import pytest from gdtoolkit.parser import parser -from ..common import GODOT_SERVER, write_project_settings, write_file - -OK_DATA_DIR = "../valid-gd-scripts" +OK_DATA_DIRS = [ + "../valid-gd-scripts", + "../formatter/input-output-pairs", +] NOK_DATA_DIR = "../invalid-gd-scripts" -BUGS_DATA_DIR = "../potential-godot-bugs" def pytest_generate_tests(metafunc): this_directory = os.path.dirname(os.path.abspath(__file__)) if "gdscript_ok_path" in metafunc.fixturenames: - directory_tests = os.path.join(this_directory, OK_DATA_DIR) - metafunc.parametrize( - "gdscript_ok_path", - [os.path.join(directory_tests, f) for f in os.listdir(directory_tests)], - ) + tests = [] + for ok_data_dir in OK_DATA_DIRS: + directory_tests = os.path.join(this_directory, ok_data_dir) + tests += [ + os.path.join(directory_tests, f) for f in os.listdir(directory_tests) + ] + metafunc.parametrize("gdscript_ok_path", tests) if "gdscript_nok_path" in metafunc.fixturenames: directory_tests = os.path.join(this_directory, NOK_DATA_DIR) metafunc.parametrize( "gdscript_nok_path", [os.path.join(directory_tests, f) for f in os.listdir(directory_tests)], ) - if "gdscript_bug_path" in metafunc.fixturenames: - directory_tests = os.path.join(this_directory, BUGS_DATA_DIR) - metafunc.parametrize( - "gdscript_bug_path", - [os.path.join(directory_tests, f) for f in os.listdir(directory_tests)], - ) +@pytest.mark.parser def test_parsing_success(gdscript_ok_path): with open(gdscript_ok_path, "r", encoding="utf-8") as handle: code = handle.read() parser.parse(code) # just checking if not throwing -@pytest.mark.skipif(shutil.which(GODOT_SERVER) is None, reason="requires godot server") -@pytest.mark.godot_check_only -def test_godot_check_only_success(gdscript_ok_path, tmp_path): - write_project_settings(tmp_path) - write_file(tmp_path, "dummy.gd", "class X:\n\tpass") - with subprocess.Popen( - [ - GODOT_SERVER, - "--headless", - "--check-only", - "-s", - gdscript_ok_path, - "--path", - tmp_path, - ], - ) as process: - process.wait() - assert process.returncode == 0 - - +@pytest.mark.parser def test_parsing_failure(gdscript_nok_path): with open(gdscript_nok_path, "r", encoding="utf-8") as handle: code = handle.read() @@ -69,23 +45,3 @@ def test_parsing_failure(gdscript_nok_path): except: # pylint: disable=bare-except return assert True, "shall fail" - - -@pytest.mark.skipif(shutil.which(GODOT_SERVER) is None, reason="requires godot server") -@pytest.mark.godot_check_only -def test_godot_check_only_failure(gdscript_nok_path): - with subprocess.Popen( - [GODOT_SERVER, "--headless", "--check-only", "-s", gdscript_nok_path], - ) as process: - process.wait() - assert process.returncode != 0 - - -@pytest.mark.skipif(shutil.which(GODOT_SERVER) is None, reason="requires godot server") -@pytest.mark.godot_check_only -def test_godot_check_only_potential_bugs(gdscript_bug_path): - with subprocess.Popen( - [GODOT_SERVER, "--headless", "--check-only", "-s", gdscript_bug_path], - ) as process: - process.wait() - assert process.returncode != 0 diff --git a/tests/potential-godot-bugs/inline_match_in_lambda.gd b/tests/potential-godot-bugs/inline_match_in_lambda.gd new file mode 100644 index 00000000..3c698e2a --- /dev/null +++ b/tests/potential-godot-bugs/inline_match_in_lambda.gd @@ -0,0 +1,3 @@ +func foo(): + var x1 = func(): if true: pass # this works + var x2 = func(): match 1: _: pass # this doesn't diff --git a/tests/valid-gd-scripts/lambdas.gd b/tests/valid-gd-scripts/lambdas.gd index 4d4bc177..530f145c 100644 --- a/tests/valid-gd-scripts/lambdas.gd +++ b/tests/valid-gd-scripts/lambdas.gd @@ -3,19 +3,9 @@ extends Node func _ready(): var l1 = func(x): pass;print('l1', x) l1.call('foo') - # var l2 = func(x): - # pass - # print('l2', x) - # l2.call('bar') var ls = [func(): print('l3'), func(): print('l4')] ls[1].call() var lss = [ - # func(): - # pass - # print('l5'), func(): print('l6')] lss[1].call() get_tree().process_frame.connect(func(): pass;print('x')) - # get_tree().process_frame.connect(func(): - # pass - # print('y')) diff --git a/tests/valid-gd-scripts/multiline_lambdas.gd b/tests/valid-gd-scripts/multiline_lambdas.gd new file mode 100644 index 00000000..2df6c11d --- /dev/null +++ b/tests/valid-gd-scripts/multiline_lambdas.gd @@ -0,0 +1,70 @@ +func foo(): + var f0 = func bar(): + pass + var f1 = func(): + pass + var f11 = func(): + var f11r = func(): + pass + var f12 = func(): + var f12r = func(): + return func(): pass + var f13 = func(): + pass + var f13r = func(): + pass + return func(): pass + var f14 = func(): + pass + var f14r = func(): + if true: + pass + var f15 = func(): + pass + var f15r = func(): + if true: + pass + pass + pass + var f16 = func(): + @warning_ignore("unused_variable") + var f17 = func(): + @warning_ignore("unused_variable") + var x + var f18 = func(): + @warning_ignore("unused_variable") var x + var f19 = func(): + @warning_ignore("unused_variable") @warning_ignore("unused_variable") var x + var f2s = [func(): + pass + ] + var f3s = [func(): + pass + pass + ] + var f4s = [func(): + pass] + var f5s = [func(): + pass + pass] + var f6s = [func(): + pass, func(): + pass] + var f7s = [func(): + return [1,2,3], func(): + pass] + var f8s = [func(): + pass + var f8sr = func(): + pass + var dct = {'f':func(): + pass + var f8srr = func(): + pass + return [1,2,3]}] + # Godot 4.3 failing: + # var fx = func(): + # pass if true else func(): + # pass + # var fx = func(): + # pass is int