├── tests ├── __init__.py ├── gd2py │ ├── __init__.py │ ├── input-output-pairs │ │ ├── empty.in.gd │ │ ├── empty.out.py │ │ ├── class_level_statements.out.py │ │ ├── func_level_statements.out.py │ │ ├── func_level_statements.in.gd │ │ └── class_level_statements.in.gd │ ├── test_python_files_compilation.py │ ├── test_conversion.py │ └── test_input_output_pairs.py ├── formatter │ ├── __init__.py │ ├── big-input-files │ │ └── dummy.gd │ ├── input-output-pairs │ │ ├── class_stmt_chain.in.gd │ │ ├── class_stmt_chain.out.gd │ │ ├── class_name_statement.in.gd │ │ ├── class_name_statement.out.gd │ │ ├── comment_corner_case.in.gd │ │ ├── bug_127_hashtag_corner_case.in.gd │ │ ├── bug_127_hashtag_corner_case.out.gd │ │ ├── comment_corner_case.out.gd │ │ ├── turn_spaces_into_tabs.in.gd │ │ ├── turn_spaces_into_tabs.out.gd │ │ ├── enum_operations.in.gd │ │ ├── class_name_w_extends_statement.in.gd │ │ ├── empty_enum.in.gd │ │ ├── enum_operations.out.gd │ │ ├── utf_8_characters.in.gd │ │ ├── utf_8_characters.out.gd │ │ ├── assert.in.gd │ │ ├── class_name_w_extends_statement.out.gd │ │ ├── empty_enum.out.gd │ │ ├── assert.out.gd │ │ ├── nested_classes.in.gd │ │ ├── nested_classes.out.gd │ │ ├── comment_at_the_end_of_file_237.in.gd │ │ ├── bug_156_trailing_comma_corner_case.in.gd │ │ ├── bug_289_breakpoing.in.gd │ │ ├── bug_289_breakpoing.out.gd │ │ ├── comment_at_the_end_of_file_237.out.gd │ │ ├── extra_function_definitions.in.gd │ │ ├── extra_function_definitions.out.gd │ │ ├── blockless_class.in.gd │ │ ├── inline_comments_on_compound_stmts.in.gd │ │ ├── multiline_string.in.gd │ │ ├── enum_w_trailing_comma.in.gd │ │ ├── multiline_string.out.gd │ │ ├── regular_enum.in.gd │ │ ├── blank_line_squeezing.out.gd │ │ ├── regular_enum.out.gd │ │ ├── bug_156_trailing_comma_corner_case.out.gd │ │ ├── bug_70_ternary_corner_case.in.gd │ │ ├── bug_70_ternary_corner_case.out.gd │ │ ├── for_loop_typed.in.gd │ │ ├── inline_comments_on_compound_stmts.out.gd │ │ ├── leading_and_trailing_wss_w_comments.out.gd │ │ ├── for_loop_typed.out.gd │ │ ├── static_variables.in.gd │ │ ├── underscored_numeric_literals.in.gd │ │ ├── static_variables.out.gd │ │ ├── underscored_numeric_literals.out.gd │ │ ├── enum_w_long_name.in.gd │ │ ├── regular_enum_force_multiline.in.gd │ │ ├── bug_136_empty_comma_separated_list.in.gd │ │ ├── enum_name_not_long_enough.in.gd │ │ ├── enum_name_not_long_enough.out.gd │ │ ├── enum_w_long_name.out.gd │ │ ├── force_multiline_array.in.gd │ │ ├── level_0_comment_preservation.in.gd │ │ ├── enhanced_operator_chain.in.gd │ │ ├── level_0_comment_preservation.out.gd │ │ ├── long_arithmetic_expression.in.gd │ │ ├── simple_class_stmts.out.gd │ │ ├── blockless_class.out.gd │ │ ├── bug_136_empty_comma_separated_list.out.gd │ │ ├── enhanced_operator_chain.out.gd │ │ ├── multiline_preload_workaround.in.gd │ │ ├── multiline_preload_workaround.out.gd │ │ ├── if_corner_case.in.gd │ │ ├── leading_and_trailing_wss_w_comments.in.gd │ │ ├── short_array_expressions.out.gd │ │ ├── multiline_content_tests.in.gd │ │ ├── short_array_expressions.in.gd │ │ ├── bug_148_complex_func_header.in.gd │ │ ├── simple_class_stmts.in.gd │ │ ├── blank_line_squeezing.in.gd │ │ ├── simple_nested_class_stmts.out.gd │ │ ├── bug_148_complex_func_header.out.gd │ │ ├── simple_content_tests.in.gd │ │ ├── static_function_surroundings.in.gd │ │ ├── type_cast_expressions.in.gd │ │ ├── bug_160_multiline_call_chaining.in.gd │ │ ├── simple_content_tests.out.gd │ │ ├── regular_enum_force_multiline.out.gd │ │ ├── assignment_expressions.in.gd │ │ ├── const_statements.out.gd │ │ ├── multiplication_division_remainder_expressions.in.gd │ │ ├── simple_nested_class_stmts.in.gd │ │ ├── const_statements.in.gd │ │ ├── enum_w_trailing_comma.out.gd │ │ ├── if_corner_case.out.gd │ │ ├── short_dict_expressions.out.gd │ │ ├── simple_classes_and_functions.in.gd │ │ ├── static_function_surroundings.out.gd │ │ ├── bug_326_multistatement_lambda_corner_case.in.gd │ │ ├── typed_dicts.in.gd │ │ ├── bug_195_dot_chain_corner_case.in.gd │ │ ├── bug_195_dot_chain_corner_case.out.gd │ │ ├── short_dict_expressions.in.gd │ │ ├── assignment_expressions.out.gd │ │ ├── simple_classes_and_functions.out.gd │ │ ├── bug_160_multiline_call_chaining.out.gd │ │ ├── if_elif_else_comments.in.gd │ │ ├── parentheses_expressions_preservation.in.gd │ │ ├── type_hints.in.gd │ │ ├── attribute_expressions.in.gd │ │ ├── if_elif_else_comments.out.gd │ │ ├── blockless_func_n_func_suite.in.gd │ │ ├── bug_339_multiline_lambda.in.gd │ │ ├── bug_205_static_func_corner_case.in.gd │ │ ├── type_hints.out.gd │ │ ├── comment_corner_cases.in.gd │ │ ├── comment_corner_cases.out.gd │ │ ├── force_multiline_array.out.gd │ │ ├── power_expressions.in.gd │ │ ├── bug_326_multistatement_lambda_corner_case.out.gd │ │ ├── parentheses_expressions_preservation.out.gd │ │ ├── simple_function_statements.in.gd │ │ ├── bug_205_static_func_corner_case.out.gd │ │ ├── bug_339_multiline_lambda.out.gd │ │ ├── addition_n_subtraction_expressions.in.gd │ │ ├── negation_n_bitwise_not_expressions.in.gd │ │ ├── multiline_content_tests.out.gd │ │ ├── test_corner_cases.in.gd │ │ ├── type_cast_expressions.out.gd │ │ ├── bug_375_warning_ignore_shadowed_variable.in.gd │ │ ├── bug_375_warning_ignore_shadowed_variable.out.gd │ │ ├── simple_function_statements.out.gd │ │ ├── short_boolean_test_expressions.in.gd │ │ ├── simple_class_statements.in.gd │ │ ├── short_boolean_test_expressions.out.gd │ │ ├── simple_class_statements.out.gd │ │ ├── complex_extends_statements.in.gd │ │ ├── complex_unistatement_lambdas.in.gd │ │ ├── typed_dicts.out.gd │ │ ├── blockless_func_n_func_suite.out.gd │ │ ├── bug_334_multiline_lambda.in.gd │ │ ├── variadic_functions.in.gd │ │ ├── await_expressions.in.gd │ │ ├── complex_extends_statements.out.gd │ │ ├── rstrings.out.gd │ │ ├── type_test_expressions.in.gd │ │ ├── compound_function_statements.in.gd │ │ ├── multiplication_division_remainder_expressions.out.gd │ │ ├── simple_multistatement_lambdas.in.gd │ │ ├── compound_function_statements.out.gd │ │ ├── rstrings.in.gd │ │ ├── bug_334_multiline_lambda.out.gd │ │ ├── test_corner_cases.out.gd │ │ ├── complex_unistatement_lambdas.out.gd │ │ ├── attribute_expressions.out.gd │ │ ├── long_atom_expressions.in.gd │ │ ├── multiline_annotations.in.gd │ │ ├── abstract_functions.out.gd │ │ ├── long_atom_expressions.out.gd │ │ ├── strings.out.gd │ │ ├── force_multiline_dict.in.gd │ │ ├── simple_annotations_w_comments.in.gd │ │ ├── subscription_expressions.in.gd │ │ ├── abstract_functions.in.gd │ │ ├── long_array_expressions.in.gd │ │ ├── regular_long_enum.in.gd │ │ ├── simple_annotations_w_comments.out.gd │ │ ├── simple_multistatement_lambdas.out.gd │ │ ├── strings.in.gd │ │ ├── long_attribute_expression_corner_case.in.gd │ │ ├── blank_line_adding.in.gd │ │ ├── await_expressions.out.gd │ │ ├── simple_annotations.out.gd │ │ ├── variadic_functions.out.gd │ │ ├── simple_annotations.in.gd │ │ ├── multiline_annotations.out.gd │ │ ├── simple_function_definitions.in.gd │ │ ├── array_n_dict_expression_comments.in.gd │ │ ├── array_n_dict_expression_comments.out.gd │ │ ├── force_multiline_dict.out.gd │ │ ├── blank_line_adding.out.gd │ │ ├── long_arithmetic_expression.out.gd │ │ ├── long_dict_expressions.in.gd │ │ ├── or_xor_and_shift_bitwise_expressions.in.gd │ │ ├── long_array_expressions.out.gd │ │ ├── multiline_properties.in.gd │ │ ├── regular_long_enum.out.gd │ │ ├── simple_function_definitions.out.gd │ │ ├── bug_326_multistatement_lambda_corner_case_workaround.in.gd │ │ ├── parentheses_expressions_removal.in.gd │ │ ├── complex_signal_statements.in.gd │ │ ├── type_test_expressions.out.gd │ │ ├── simple_atom_expressions.in.gd │ │ ├── multiline_properties.out.gd │ │ ├── parentheses_expressions_removal.out.gd │ │ ├── complex_trailing_comma_scenarios.in.gd │ │ ├── call_expressions.in.gd │ │ ├── enum_comments.in.gd │ │ ├── enum_comments.out.gd │ │ ├── simple_atom_expressions.out.gd │ │ ├── addition_n_subtraction_expressions.out.gd │ │ ├── complex_trailing_comma_scenarios.out.gd │ │ ├── long_multistatement_lambdas.in.gd │ │ ├── standalone_comments_in_expressions.in.gd │ │ ├── bug_326_multistatement_lambda_corner_case_workaround.out.gd │ │ ├── multiline_annotations_w_comments.in.gd │ │ ├── multiline_annotations_w_comments.out.gd │ │ ├── standalone_comments_in_expressions.out.gd │ │ ├── inline_properties.in.gd │ │ ├── long_boolean_test_expressions.in.gd │ │ ├── complex_signal_statements.out.gd │ │ ├── simple_match_statements.in.gd │ │ ├── type_cast_corner_case_expressions.in.gd │ │ ├── subscription_expressions.out.gd │ │ ├── simple_match_statements.out.gd │ │ ├── long_dict_expressions.out.gd │ │ ├── multiline_properties_w_comments.in.gd │ │ ├── multiline_properties_w_comments.out.gd │ │ ├── inline_properties.out.gd │ │ ├── inline_properties_w_comments.in.gd │ │ ├── negation_n_bitwise_not_expressions.out.gd │ │ ├── inline_lambdas_w_comments.in.gd │ │ ├── long_attribute_expression_corner_case.out.gd │ │ ├── complex_function_definitions.in.gd │ │ ├── inline_properties_w_comments.out.gd │ │ ├── complex_dot_chains.in.gd │ │ ├── power_expressions.out.gd │ │ ├── call_expressions.out.gd │ │ ├── long_boolean_test_expressions.out.gd │ │ ├── complex_function_definitions.out.gd │ │ ├── or_xor_and_shift_bitwise_expressions.out.gd │ │ ├── inline_lambdas_w_comments.out.gd │ │ ├── simple_unistatement_lambdas.out.gd │ │ ├── simple_unistatement_lambdas.in.gd │ │ ├── long_multistatement_lambdas.out.gd │ │ ├── long_unistatement_lambdas.in.gd │ │ └── type_cast_corner_case_expressions.out.gd │ ├── common.py │ ├── test_real_world_scripts.py │ ├── test_input_output_pairs.py │ └── test_basics.py ├── gdradon │ ├── __init__.py │ └── test_executable.py ├── generated │ └── __init__.py ├── linter │ ├── __init__.py │ ├── test_basic_corner_cases.py │ ├── test_linter.py │ ├── common.py │ ├── test_class_checks.py │ └── test_gdlint_ignore.py ├── parser │ ├── __init__.py │ └── test_parser.py ├── valid-gd-scripts │ ├── empty.gd │ ├── newline.gd │ ├── oneliner.gd │ ├── comments_only.gd │ ├── endlineless_annotation.gd │ ├── newlineless_class_flat.gd │ ├── class_name.gd │ ├── extends.gd │ ├── newlineless_func.gd │ ├── newlines.gd │ ├── extends2.gd │ ├── newlineless_class.gd │ ├── class_to_extend.gd │ ├── const_dict.gd │ ├── export.gd │ ├── class_name_w_extends.gd │ ├── newlineless_func_w_if.gd │ ├── newlineless_func_recursive.gd │ ├── annotation_w_empty_body_54279.gd │ ├── multiline_preload.gd │ ├── newlineless_class_recursive.gd │ ├── trailing_comma_after_formal_parameter.gd │ ├── dotted_types.gd │ ├── multiline_type_cast.gd │ ├── comment_at_the_end_of_file_237.gd │ ├── extends3.gd │ ├── match_w_arr_w_trailing_comma.gd │ ├── docstrings.gd │ ├── newlines2.gd │ ├── trailing_comma_after_actual_parameter.gd │ ├── multiline_subscription_expression.gd │ ├── unresolved_assign.gd │ ├── default_func_params.gd │ ├── outer_scope_enum.gd │ ├── multiline_dict_w_eq_sign.gd │ ├── oneliners.gd │ ├── complex_signal_statements.gd │ ├── type_testing_with_typed_arrays_54312.gd │ ├── typed_for_loop.gd │ ├── static_variables.gd │ ├── multiline_attribute_expression.gd │ ├── enum_w_type_cast.gd │ ├── edge_if.gd │ ├── endlineless_inner_annotation.gd │ ├── simple_statements.gd │ ├── set_function_call_228.gd │ ├── unique_node_name.gd │ ├── constants.gd │ ├── signals.gd │ ├── edge_func_args.gd │ ├── funcs_and_calls.gd │ ├── rstrings.gd │ ├── multiline_expressions.gd │ ├── call_expr.gd │ ├── variadic_functions.gd │ ├── match_w_multiline_arr_n_dict_85867.gd │ ├── typed_dicts.gd │ ├── node_paths.gd │ ├── comments.gd │ ├── multiline_annotations_66322.gd │ ├── semicolon.gd │ ├── blockless_func_n_func_suite.gd │ ├── type_cast.gd │ ├── lambdas.gd │ ├── static_typing.gd │ ├── abstract_functions.gd │ ├── array_values.gd │ ├── typed_arrays.gd │ ├── bug_327_multiline_lambda.gd │ ├── mixed_type_case_n_test_expression.gd │ ├── dict_values.gd │ ├── enums.gd │ ├── functions.gd │ ├── function_annotations.gd │ ├── annotations.gd │ ├── literals.gd │ ├── expressions.gd │ ├── edge_func_calls.gd │ ├── properties.gd │ ├── await.gd │ └── multiline_lambdas.gd ├── invalid-gd-scripts │ ├── empty_setget.gd │ ├── onready_var.gd │ ├── class_name2.gd │ ├── dict.gd │ ├── dict2.gd │ ├── empty_func.gd │ ├── enum_wo_commas.gd │ ├── legacy_assert.gd │ ├── chained_comparison.gd │ ├── static_variables.gd │ ├── dot_super_call.gd │ ├── type_cast_w_subscription.gd │ ├── type_cast_w_attrcall.gd │ ├── standalone_trailing_comma_in_formal_parameters.gd │ ├── match_w_dict_w_eq.gd │ ├── match_w_dict_w_eq_2.gd │ ├── constructor_chain.gd │ ├── standalone_trailing_comma_in_actual_parameters.gd │ ├── variadic_functions.gd │ ├── var_in_func_args.gd │ ├── apos_docstring.gd │ └── setget.gd ├── potential-godot-bugs │ ├── weird_class_stmt_chain.gd │ ├── oneliners.gd │ ├── lowlvl_exprs_mixed_w_type_cast.gd │ ├── annotation_w_semicolon_corner_case_54280.gd │ ├── inline_match_in_lambda.gd │ ├── match_w_multiline_list_85760.gd │ └── lambda_corner_case.gd ├── conftest.py └── common.py ├── gdtoolkit ├── __init__.py ├── common │ ├── __init__.py │ ├── types.py │ ├── exceptions.py │ └── utils.py ├── gdradon │ └── __init__.py ├── parser │ ├── __init__.py │ └── comments.lark ├── linter │ ├── helpers.py │ ├── types.py │ ├── problem.py │ ├── problem_printer.py │ └── misc_checks.py ├── formatter │ ├── types.py │ ├── statement_utils.py │ ├── exceptions.py │ ├── constants.py │ ├── const_statement.py │ └── __init__.py └── gd2py │ └── __main__.py ├── makefile ├── .github ├── FUNDING.yml └── workflows │ ├── tests.yml │ └── deploy.yml ├── MANIFEST.in ├── stubs └── lark │ ├── tree.pyi │ └── __init__.pyi ├── setup.cfg ├── .gitignore ├── pylintrc ├── .pre-commit-hooks.yaml ├── action.yml ├── LICENSE └── setup.py /tests/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gdtoolkit/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/gd2py/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gdtoolkit/common/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/formatter/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/gdradon/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/generated/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/linter/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/parser/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /gdtoolkit/gdradon/__init__.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /makefile: -------------------------------------------------------------------------------- 1 | all: 2 | pytest -v 3 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/empty.gd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/newline.gd: -------------------------------------------------------------------------------- 1 | 2 | -------------------------------------------------------------------------------- /.github/FUNDING.yml: -------------------------------------------------------------------------------- 1 | ko_fi: pawel_lampe 2 | -------------------------------------------------------------------------------- /tests/formatter/big-input-files/dummy.gd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/gd2py/input-output-pairs/empty.in.gd: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/gd2py/input-output-pairs/empty.out.py: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/oneliner.gd: -------------------------------------------------------------------------------- 1 | pass 2 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/comments_only.gd: -------------------------------------------------------------------------------- 1 | # xx 2 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/endlineless_annotation.gd: -------------------------------------------------------------------------------- 1 | @tool -------------------------------------------------------------------------------- /tests/valid-gd-scripts/newlineless_class_flat.gd: -------------------------------------------------------------------------------- 1 | pass -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/empty_setget.gd: -------------------------------------------------------------------------------- 1 | var x setget 2 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/onready_var.gd: -------------------------------------------------------------------------------- 1 | onready var x 2 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/class_name.gd: -------------------------------------------------------------------------------- 1 | class_name Dummy 2 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/extends.gd: -------------------------------------------------------------------------------- 1 | extends "res://dummy.gd" 2 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/newlineless_func.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | pass -------------------------------------------------------------------------------- /tests/valid-gd-scripts/newlines.gd: -------------------------------------------------------------------------------- 1 | 2 | 3 | 4 | 5 | 6 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/class_name2.gd: -------------------------------------------------------------------------------- 1 | class_name Dummy, "asdf" 2 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/dict.gd: -------------------------------------------------------------------------------- 1 | var mixed = {x = 2, 'y': 1} 2 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/dict2.gd: -------------------------------------------------------------------------------- 1 | var mixed2 = {'y': 1, x = 2} 2 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/empty_func.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | # xxx 3 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/enum_wo_commas.gd: -------------------------------------------------------------------------------- 1 | enum { A = 0 B = 1 } 2 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/extends2.gd: -------------------------------------------------------------------------------- 1 | extends "res://dummy.gd".X 2 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/newlineless_class.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | pass 3 | -------------------------------------------------------------------------------- /gdtoolkit/parser/__init__.py: -------------------------------------------------------------------------------- 1 | from .parser import parser # noqa: F401 2 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/class_stmt_chain.in.gd: -------------------------------------------------------------------------------- 1 | var x;var y 2 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/class_to_extend.gd: -------------------------------------------------------------------------------- 1 | func _init(a, b): 2 | pass 3 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/const_dict.gd: -------------------------------------------------------------------------------- 1 | const X = { 2 | 'x': [], 3 | } 4 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/export.gd: -------------------------------------------------------------------------------- 1 | pass 2 | 3 | # TODO: add exports 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/class_stmt_chain.out.gd: -------------------------------------------------------------------------------- 1 | var x 2 | var y 3 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/legacy_assert.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | assert 1 == 1 3 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/class_name_statement.in.gd: -------------------------------------------------------------------------------- 1 | class_name Some 2 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/class_name_statement.out.gd: -------------------------------------------------------------------------------- 1 | class_name Some 2 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/comment_corner_case.in.gd: -------------------------------------------------------------------------------- 1 | var x;var y # xxx 2 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/chained_comparison.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | 1 == 1 == 1 3 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/static_variables.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | static var x = 1 3 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/class_name_w_extends.gd: -------------------------------------------------------------------------------- 1 | class_name Dummy extends Node 2 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/newlineless_func_w_if.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | if true: 3 | pass -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_127_hashtag_corner_case.in.gd: -------------------------------------------------------------------------------- 1 | var x = "#" # 2 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_127_hashtag_corner_case.out.gd: -------------------------------------------------------------------------------- 1 | var x = "#" # 2 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/comment_corner_case.out.gd: -------------------------------------------------------------------------------- 1 | var x 2 | var y # xxx 3 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/turn_spaces_into_tabs.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | pass 3 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/turn_spaces_into_tabs.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | pass 3 | -------------------------------------------------------------------------------- /tests/potential-godot-bugs/weird_class_stmt_chain.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | @tool;var x 3 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/newlineless_func_recursive.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | pass -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/dot_super_call.gd: -------------------------------------------------------------------------------- 1 | func _process(delta): 2 | .process(delta) 3 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/type_cast_w_subscription.gd: -------------------------------------------------------------------------------- 1 | func foo(x): 2 | [1] as Array [0] 3 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/annotation_w_empty_body_54279.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | @onready() var x 3 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/multiline_preload.gd: -------------------------------------------------------------------------------- 1 | var x = preload( 2 | 'res://dummy.gd' 3 | ) 4 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/newlineless_class_recursive.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | class Y: 3 | pass 4 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/trailing_comma_after_formal_parameter.gd: -------------------------------------------------------------------------------- 1 | func foo(a,): 2 | pass 3 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include gdtoolkit/parser/gdscript.lark 2 | include gdtoolkit/parser/comments.lark 3 | -------------------------------------------------------------------------------- /stubs/lark/tree.pyi: -------------------------------------------------------------------------------- 1 | class Meta: 2 | line: int 3 | column: int 4 | end_line: int 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enum_operations.in.gd: -------------------------------------------------------------------------------- 1 | enum {SOME_A = 1 + 1, SOME_B= 1<<1} 2 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/type_cast_w_attrcall.gd: -------------------------------------------------------------------------------- 1 | func foo(x): 2 | x as Node . name . size() 3 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/dotted_types.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | class Y: 3 | pass 4 | 5 | var x: X.Y 6 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/multiline_type_cast.gd: -------------------------------------------------------------------------------- 1 | var x = ( 2 | 1 3 | as int 4 | as int 5 | ) 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/class_name_w_extends_statement.in.gd: -------------------------------------------------------------------------------- 1 | class_name Foo extends Node 2 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/empty_enum.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | enum{} 3 | enum SomeEnumName{} 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enum_operations.out.gd: -------------------------------------------------------------------------------- 1 | enum { SOME_A = 1 + 1, SOME_B = 1 << 1 } 2 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/utf_8_characters.in.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | var a = {"啊":1} 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/utf_8_characters.out.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | var a = {"啊": 1} 4 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/standalone_trailing_comma_in_formal_parameters.gd: -------------------------------------------------------------------------------- 1 | func bar(,): 2 | pass 3 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/comment_at_the_end_of_file_237.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var a = 1 3 | # # var i = 2 -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/assert.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | assert (1==1) 3 | assert (1==1,"asdf") 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/class_name_w_extends_statement.out.gd: -------------------------------------------------------------------------------- 1 | class_name Foo extends Node 2 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/empty_enum.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | enum {} 3 | enum SomeEnumName {} 4 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/extends3.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | class Y: 3 | pass 4 | 5 | class Z: 6 | extends X.Y 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [metadata] 2 | long_description = file: README.md 3 | long_description_content_type = text/markdown 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/assert.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | assert(1 == 1) 3 | assert(1 == 1, "asdf") 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/nested_classes.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | class Y: 3 | class Z: 4 | pass 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/nested_classes.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | class Y: 3 | class Z: 4 | pass 5 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/match_w_dict_w_eq.gd: -------------------------------------------------------------------------------- 1 | func bad(x): 2 | match x: 3 | {"x": 1, y=2}: 4 | pass 5 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/match_w_dict_w_eq_2.gd: -------------------------------------------------------------------------------- 1 | func bad(x): 2 | match x: 3 | {"x"=1, y=2}: 4 | pass 5 | -------------------------------------------------------------------------------- /tests/potential-godot-bugs/oneliners.gd: -------------------------------------------------------------------------------- 1 | class X: func foo(): pass 2 | 3 | class Y extends Reference: pass 4 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/match_w_arr_w_trailing_comma.gd: -------------------------------------------------------------------------------- 1 | func bad(x): 2 | match x: 3 | [1,2,]: 4 | pass 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/comment_at_the_end_of_file_237.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var a = 1 3 | # # var i = 2 -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_156_trailing_comma_corner_case.in.gd: -------------------------------------------------------------------------------- 1 | var x = { 2 | 0:1, 3 | 1:2, 4 | }.get(3,99) 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_289_breakpoing.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | breakpoint 3 | if true: 4 | breakpoint 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_289_breakpoing.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | breakpoint 3 | if true: 4 | breakpoint 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/comment_at_the_end_of_file_237.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var a = 1 3 | # # var i = 2 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/extra_function_definitions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | static func foo(): 3 | return null 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/extra_function_definitions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | static func foo(): 3 | return null 4 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/constructor_chain.gd: -------------------------------------------------------------------------------- 1 | extends "class_to_extend.gd" 2 | 3 | func _init(x).(x, 2): 4 | pass 5 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/docstrings.gd: -------------------------------------------------------------------------------- 1 | """docstr1 2 | """ 3 | 4 | "docstr2" 5 | 6 | 'docstr3' 7 | 8 | '''docstr4''' 9 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/newlines2.gd: -------------------------------------------------------------------------------- 1 | class_name X 2 | 3 | 4 | func foo(): 5 | 6 | 7 | pass 8 | 9 | pass 10 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/trailing_comma_after_actual_parameter.gd: -------------------------------------------------------------------------------- 1 | func foo(a): 2 | pass 3 | func bar(): 4 | foo(1,) 5 | -------------------------------------------------------------------------------- /gdtoolkit/common/types.py: -------------------------------------------------------------------------------- 1 | from typing import Union 2 | 3 | from lark import Tree, Token 4 | 5 | Node = Union[Tree, Token] 6 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/standalone_trailing_comma_in_actual_parameters.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | pass 3 | func bar(): 4 | foo(,) 5 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/variadic_functions.gd: -------------------------------------------------------------------------------- 1 | func foo(...args,a): 2 | pass 3 | func bar(a,...args=[1,2,3]): 4 | pass 5 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/multiline_subscription_expression.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(p): 3 | var x = p[ 4 | 1 5 | ] 6 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/unresolved_assign.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(z): 3 | var x 4 | x = 1 5 | x += 1 6 | x = {} 7 | -------------------------------------------------------------------------------- /gdtoolkit/linter/helpers.py: -------------------------------------------------------------------------------- 1 | def is_function_public(function_name: str) -> bool: 2 | return not function_name.startswith("_") 3 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/blockless_class.in.gd: -------------------------------------------------------------------------------- 1 | var a 2 | class X: var b;var c 3 | var d 4 | class Y: var e 5 | var f 6 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/default_func_params.gd: -------------------------------------------------------------------------------- 1 | func bar(): 2 | pass 3 | 4 | func foo(a = 5, b = 5 + 7, c = bar()): 5 | pass 6 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/outer_scope_enum.gd: -------------------------------------------------------------------------------- 1 | enum { QWE, ASD } 2 | class X: 3 | func foo(ev): 4 | var x = QWE 5 | var y = ASD 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/inline_comments_on_compound_stmts.in.gd: -------------------------------------------------------------------------------- 1 | pass 2 | class X: # aaa 3 | func foo(): # bbb 4 | pass 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_string.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = """aaa 4 | bbb 5 | ccc 6 | """ 7 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/multiline_dict_w_eq_sign.gd: -------------------------------------------------------------------------------- 1 | var y = { name = 1 } # fine 2 | var x = { 3 | name = # parse errror 4 | 1 5 | } 6 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/oneliners.gd: -------------------------------------------------------------------------------- 1 | func foo(): pass 2 | 3 | # class X: func foo(): pass 4 | 5 | # class Y extends Reference: pass 6 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | __pycache__ 2 | misc/ 3 | .tox 4 | gdtoolkit.egg-info/ 5 | .mypy_cache/ 6 | dist/ 7 | /logs 8 | build 9 | .hypothesis/ 10 | -------------------------------------------------------------------------------- /gdtoolkit/linter/types.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class Range: 6 | begin: int 7 | end: int 8 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enum_w_trailing_comma.in.gd: -------------------------------------------------------------------------------- 1 | enum {A,B,C,} 2 | enum {D,E,F=3,} 3 | enum X{G,H,I,} 4 | enum Y{J,K,L=3,} 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_string.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = """aaa 4 | bbb 5 | ccc 6 | """ 7 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/regular_enum.in.gd: -------------------------------------------------------------------------------- 1 | enum {SOME_A,SOME_B=1, SOME_C=2} 2 | enum Named { SOME_A ,SOME_B = 1, SOME_C =2 } 3 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/var_in_func_args.gd: -------------------------------------------------------------------------------- 1 | func foo(x, y, z: int, q: int, w = 7, e: int = 7, r: int = 7, t := 8, var u := 9): 2 | pass 3 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/complex_signal_statements.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | signal a(x, y) # ok 3 | # nok: 4 | signal b( 5 | x, 6 | y 7 | ) 8 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/type_testing_with_typed_arrays_54312.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | func _ready(): 5 | print([1,2.1] is Array[int]) 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/blank_line_squeezing.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | # aaa 4 | 5 | pass # bbb 6 | 7 | # ccc 8 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/regular_enum.out.gd: -------------------------------------------------------------------------------- 1 | enum { SOME_A, SOME_B = 1, SOME_C = 2 } 2 | enum Named { SOME_A, SOME_B = 1, SOME_C = 2 } 3 | -------------------------------------------------------------------------------- /tests/potential-godot-bugs/lowlvl_exprs_mixed_w_type_cast.gd: -------------------------------------------------------------------------------- 1 | func foo(x): 2 | x as Node . name # ok 3 | x as Node . name . size() # nok(?) 4 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/typed_for_loop.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func _ready(): 4 | var a: Array[int] = [1] 5 | for i: int in a: 6 | print(a) 7 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_156_trailing_comma_corner_case.out.gd: -------------------------------------------------------------------------------- 1 | var x = ( 2 | { 3 | 0: 1, 4 | 1: 2, 5 | } 6 | . get(3, 99) 7 | ) 8 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_70_ternary_corner_case.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var direction = 1 if 0 % 2 == 0 else - 1 3 | print(direction) 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_70_ternary_corner_case.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var direction = 1 if 0 % 2 == 0 else -1 3 | print(direction) 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/for_loop_typed.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var a: Array[int] = [1] 4 | for i:int in a: 5 | print(a[i]) -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/inline_comments_on_compound_stmts.out.gd: -------------------------------------------------------------------------------- 1 | pass 2 | 3 | 4 | class X: # aaa 5 | func foo(): # bbb 6 | pass 7 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/leading_and_trailing_wss_w_comments.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | # aaa 4 | pass # bbb 5 | # ccc 6 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/static_variables.gd: -------------------------------------------------------------------------------- 1 | static var a 2 | static var b = 1 3 | static var c : int 4 | static var d : int = 1 5 | static var e := 1 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/for_loop_typed.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var a: Array[int] = [1] 4 | for i: int in a: 5 | print(a[i]) 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/static_variables.in.gd: -------------------------------------------------------------------------------- 1 | static var a 2 | static var b=1 3 | static var c:int 4 | static var d:int=1 5 | static var e:=1 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/underscored_numeric_literals.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | 1_000_000>0 3 | 1_000.000>0.0 4 | 0xff_99_00>0 5 | 0b11_11_11>0 6 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/multiline_attribute_expression.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(p): 3 | var x = ( 4 | p 5 | .some 6 | .some 7 | .some 8 | ) 9 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/static_variables.out.gd: -------------------------------------------------------------------------------- 1 | static var a 2 | static var b = 1 3 | static var c: int 4 | static var d: int = 1 5 | static var e := 1 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/underscored_numeric_literals.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | 1_000_000 > 0 3 | 1_000.000 > 0.0 4 | 0xff_99_00 > 0 5 | 0b11_11_11 > 0 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enum_w_long_name.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | enum XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX {} 3 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/regular_enum_force_multiline.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | enum {SOME_A,SOME_B=1, SOME_C=2,} 3 | enum Named { SOME_A ,SOME_B = 1, SOME_C =2, } 4 | -------------------------------------------------------------------------------- /tests/potential-godot-bugs/annotation_w_semicolon_corner_case_54280.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | pass;pass # ok 3 | @onready var x;pass # ok 4 | @onready;var y;pass # no-ok 5 | -------------------------------------------------------------------------------- /tests/potential-godot-bugs/inline_match_in_lambda.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var x1 = func(): if true: pass # this works 3 | var x2 = func(): match 1: _: pass # this doesn't 4 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/enum_w_type_cast.gd: -------------------------------------------------------------------------------- 1 | enum Named { Foo, Bar = 1 if true else 0 } 2 | enum Named2 { Foo, Bar = 1 << 3 } 3 | enum Named3 { Foo, Bar = 1.5 as int } 4 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/edge_if.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | pass 3 | # ccc 4 | if true: 5 | pass 6 | # ccc 7 | elif true: 8 | pass 9 | # ccc 10 | else: 11 | pass 12 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/endlineless_inner_annotation.gd: -------------------------------------------------------------------------------- 1 | # TODO: uncomment if there is some annotation which may be put in this level 2 | # class X: 3 | # @tool # no newline 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_136_empty_comma_separated_list.in.gd: -------------------------------------------------------------------------------- 1 | var x= [ 2 | # TODO: fix indent 3 | ] 4 | func foo(): 5 | var y=[ 6 | # TODO: fix indent 7 | ] 8 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enum_name_not_long_enough.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | enum XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX {} 3 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enum_name_not_long_enough.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | enum XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX {} 3 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enum_w_long_name.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | enum XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX { 3 | } 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/force_multiline_array.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = [1,2,3,] 4 | var y = [[1,2,3],[4,5,6],] 5 | var z = [[1,2,3],[4,5,6,]] 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/level_0_comment_preservation.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | # aaa 3 | var x 4 | # bbb 5 | if true: 6 | # ccc 7 | pass 8 | # ddd 9 | # eee 10 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enhanced_operator_chain.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 3 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/level_0_comment_preservation.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | # aaa 3 | var x 4 | # bbb 5 | if true: 6 | # ccc 7 | pass 8 | # ddd 9 | # eee 10 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/simple_statements.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | class_name Asdf 3 | var foo 4 | var fuu = 534 5 | const bar = 123 6 | const baz = 123 7 | var is_enabled : = true 8 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_arithmetic_expression.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = 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 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_class_stmts.out.gd: -------------------------------------------------------------------------------- 1 | # aaa 2 | pass 3 | var x 4 | # bbb 5 | 6 | var y 7 | 8 | var z # ccc 9 | 10 | # ddd 11 | var q 12 | var w 13 | # eee 14 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/set_function_call_228.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func reset_to_factory_settings(sections, section, key) -> void: 4 | var value = sections[section][key] 5 | set(key, value) 6 | -------------------------------------------------------------------------------- /gdtoolkit/linter/problem.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | 4 | @dataclass 5 | class Problem: 6 | name: str 7 | description: str 8 | line: int 9 | column: int 10 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/blockless_class.out.gd: -------------------------------------------------------------------------------- 1 | var a 2 | 3 | 4 | class X: 5 | var b 6 | var c 7 | 8 | 9 | var d 10 | 11 | 12 | class Y: 13 | var e 14 | 15 | 16 | var f 17 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_136_empty_comma_separated_list.out.gd: -------------------------------------------------------------------------------- 1 | var x = [ 2 | # TODO: fix indent 3 | ] 4 | 5 | 6 | func foo(): 7 | var y = [ 8 | # TODO: fix indent 9 | ] 10 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enhanced_operator_chain.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = ( 3 | 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 + 1 4 | ) 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_preload_workaround.in.gd: -------------------------------------------------------------------------------- 1 | const Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = preload( 2 | 'class_stmt_chain.in.gd' 3 | ) 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_preload_workaround.out.gd: -------------------------------------------------------------------------------- 1 | const Xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = preload( 2 | "class_stmt_chain.in.gd" 3 | ) 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/if_corner_case.in.gd: -------------------------------------------------------------------------------- 1 | func foo(Global): 2 | if true: 3 | if !Global.current_project.layers[Global.current_project.current_layer].can_layer_get_drawn(): 4 | return 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/leading_and_trailing_wss_w_comments.in.gd: -------------------------------------------------------------------------------- 1 | 2 | 3 | class X: 4 | 5 | func foo(): 6 | 7 | # aaa 8 | pass # bbb 9 | # ccc 10 | 11 | 12 | 13 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/short_array_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = [1, 2, 3] 4 | var y = [[1, 2, 3], [4, 5, 6]] 5 | var z = [[[1, 2], [3, 4]], [[5, 6], [7, 8]]] 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_content_tests.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var a =not 1 in [1] in [true,] 3 | var b =not 1 not in [1] not in [true,] 4 | var c=not(1 not in [1] not 5 | in [true,]) 6 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/unique_node_name.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func foo(): 4 | var x = $%UniqueNodeName 5 | var y = %UniqueNodeName 6 | var z = %"a/b/c" 7 | var w = %UniqueNodeName/%AnotherUniqueNodeName 8 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/short_array_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = [1,2,3] 4 | var y = [[1,2,3],[4,5,6]] 5 | var z = [ 6 | [[1,2],[3,4]], 7 | [[5,6],[7,8]] 8 | ] 9 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/constants.gd: -------------------------------------------------------------------------------- 1 | const X = 1 2 | const Y := 1 3 | const Z : int = 1 4 | # const Q : int := 1 # illegal 5 | 6 | func foo(): 7 | const Q = 1 8 | const W := 1 9 | const E : int = 1 10 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_148_complex_func_header.in.gd: -------------------------------------------------------------------------------- 1 | func decompress_lzw(code_stream_data: PackedByteArray, min_code_size: int, colors: PackedByteArray) -> PackedByteArray: 2 | return code_stream_data 3 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_class_stmts.in.gd: -------------------------------------------------------------------------------- 1 | 2 | 3 | # aaa 4 | pass 5 | var x 6 | # bbb 7 | 8 | var y 9 | 10 | var z # ccc 11 | 12 | # ddd 13 | var q 14 | var w 15 | # eee 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/signals.gd: -------------------------------------------------------------------------------- 1 | signal aaa 2 | signal bbb (ccc) 3 | signal ccc (ddd, eee ) 4 | signal empty() 5 | signal w_trailing_comma(a,b,) 6 | signal w_types(a:int,) 7 | signal w_types_2(a:float,b:int,c,d) 8 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/blank_line_squeezing.in.gd: -------------------------------------------------------------------------------- 1 | 2 | 3 | class X: 4 | 5 | 6 | func foo(): 7 | 8 | 9 | # aaa 10 | 11 | 12 | pass # bbb 13 | 14 | 15 | # ccc 16 | 17 | 18 | 19 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_nested_class_stmts.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | # aaa 3 | pass 4 | var x 5 | # bbb 6 | 7 | var y 8 | 9 | var z # ccc 10 | 11 | # ddd 12 | var q 13 | var w 14 | # eee 15 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/edge_func_args.gd: -------------------------------------------------------------------------------- 1 | func foo(aaa, 2 | bbb, 3 | ccc,ddd): 4 | pass 5 | 6 | func bar( 7 | xxx, 8 | yyy, zzz 9 | ): 10 | pass 11 | 12 | func baz( 13 | xxx, 14 | yyy, zzz): 15 | pass 16 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/funcs_and_calls.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func foo(): 4 | pass 5 | 6 | func bar(a,b,c): 7 | pass 8 | 9 | func exec(): 10 | foo() 11 | bar(1,2,3) 12 | 13 | func bat(x := 1): 14 | pass 15 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_148_complex_func_header.out.gd: -------------------------------------------------------------------------------- 1 | func decompress_lzw( 2 | code_stream_data: PackedByteArray, min_code_size: int, colors: PackedByteArray 3 | ) -> PackedByteArray: 4 | return code_stream_data 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_content_tests.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var a =1 in [1] 3 | var b =1 in [1] in [true] 4 | var c =not 1 in [1] in [true] 5 | var e =1 not in [1] 6 | var f =not 1 not in [1] not in [true] 7 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/static_function_surroundings.in.gd: -------------------------------------------------------------------------------- 1 | static func foo(): 2 | pass 3 | static func bar(): 4 | pass 5 | class Foo: 6 | static func foo(): 7 | pass 8 | static func bar(): 9 | pass 10 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/type_cast_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = 1 as int as int 4 | var y = 1 as int as int as int as int as int as int as int as int as int as int as int as int as int 5 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/rstrings.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | print(r'" \' \ \\') 3 | print(r"\" ' \ \\") 4 | print(r"""aaa""") 5 | print(r'''bbb''') 6 | 7 | func corner_case(r): 8 | for x in r: 9 | pass 10 | var rx = 1 11 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_160_multiline_call_chaining.in.gd: -------------------------------------------------------------------------------- 1 | func do_some_stuff(x): 2 | return x 3 | func foo(): 4 | do_some_stuff(["with", "a", "decently", "long", "array", "of", "strings", "and", "other"]).is_cool() 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_content_tests.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var a = 1 in [1] 3 | var b = 1 in [1] in [true] 4 | var c = not 1 in [1] in [true] 5 | var e = 1 not in [1] 6 | var f = not 1 not in [1] not in [true] 7 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/multiline_expressions.gd: -------------------------------------------------------------------------------- 1 | func bar(s): 2 | pass 3 | 4 | func foo(): 5 | 1 == \ 6 | 2 7 | var x 8 | x.new(1 9 | ) 10 | x.new( 11 | 1, 12 | 2 13 | ) 14 | pass 15 | bar(('x' + 16 | 'y')) 17 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/regular_enum_force_multiline.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | enum { 3 | SOME_A, 4 | SOME_B = 1, 5 | SOME_C = 2, 6 | } 7 | enum Named { 8 | SOME_A, 9 | SOME_B = 1, 10 | SOME_C = 2, 11 | } 12 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/call_expr.gd: -------------------------------------------------------------------------------- 1 | func bar(): 2 | pass 3 | 4 | func foo(): 5 | var xxx 6 | bar() 7 | xxx.aaa() 8 | xxx.yyy.aaa() 9 | xxx[0].aaa() 10 | xxx[0].yyy[1].aaa() 11 | xxx.yyy[0].aaa() 12 | bar().xxx[0].aaa() 13 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/variadic_functions.gd: -------------------------------------------------------------------------------- 1 | func foo(...args): 2 | pass 3 | func bar(a,...args): 4 | pass 5 | func baz(a,...args,): 6 | pass 7 | func bat(a,...args:Array): 8 | pass 9 | func ban(a,...args:Array,): 10 | pass 11 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/assignment_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(z): 3 | var x 4 | x = 1 5 | x += 1 6 | x**=2 7 | z[[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] 8 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/const_statements.out.gd: -------------------------------------------------------------------------------- 1 | const a = 1 2 | const b = 1 + 1 3 | const c := 1 4 | const d: int = 1 5 | 6 | 7 | func foo(): 8 | const q = 1 9 | const w = 1 + 1 10 | const e := 1 11 | const r: int = 1 12 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiplication_division_remainder_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = 1 * 2 / 2 % 2 4 | var y = 1 * 2 / 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 % 2 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_nested_class_stmts.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | 3 | # aaa 4 | pass 5 | var x 6 | # bbb 7 | 8 | var y 9 | 10 | var z # ccc 11 | 12 | # ddd 13 | var q 14 | var w 15 | # eee 16 | 17 | 18 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/const_statements.in.gd: -------------------------------------------------------------------------------- 1 | const a = 1 2 | const b = 1 + 1 3 | const c : = 1 4 | const d : int = 1 5 | 6 | 7 | func foo(): 8 | const q = 1 9 | const w = 1 + 1 10 | const e : = 1 11 | const r : int = 1 12 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/match_w_multiline_arr_n_dict_85867.gd: -------------------------------------------------------------------------------- 1 | func foo(x): 2 | match x: 3 | [1, 2]: 4 | pass 5 | {"a": 1}: 6 | pass 7 | [ 8 | 2, 9 | 3 10 | ]: 11 | pass 12 | { 13 | "a": 1 14 | }: 15 | pass 16 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/typed_dicts.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var d : Dictionary[String, int] 3 | var d2 :Dictionary[int, int] = { 1: 2 } 4 | var d3 :Dictionary[int, int] = { 1: 2,2:3,3:4,4:5,5:6,6:7,7:8,8:9,9:10,10:11,11:12,12:13,13:14,14:15,15:16 } 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enum_w_trailing_comma.out.gd: -------------------------------------------------------------------------------- 1 | enum { 2 | A, 3 | B, 4 | C, 5 | } 6 | enum { 7 | D, 8 | E, 9 | F = 3, 10 | } 11 | enum X { 12 | G, 13 | H, 14 | I, 15 | } 16 | enum Y { 17 | J, 18 | K, 19 | L = 3, 20 | } 21 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/if_corner_case.out.gd: -------------------------------------------------------------------------------- 1 | func foo(Global): 2 | if true: 3 | if !( 4 | Global 5 | . current_project 6 | . layers[Global.current_project.current_layer] 7 | . can_layer_get_drawn() 8 | ): 9 | return 10 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/short_dict_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = {"a": 1, "b": 2, 1: 6} 4 | var y = {{"a": 1, "b": 2}: {1: 6}} 5 | var z = {{"a": 1, "b": 1}: {"a": 1, "b": 1}, {"a": 1, "b": 1}: {"a": 1, "b": 1}} 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_classes_and_functions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | pass 3 | 4 | func foo(): 5 | pass 6 | 7 | class Y: 8 | func bar(): 9 | pass 10 | 11 | class Z: 12 | pass 13 | 14 | class Q: 15 | class W: 16 | pass 17 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/static_function_surroundings.out.gd: -------------------------------------------------------------------------------- 1 | static func foo(): 2 | pass 3 | 4 | 5 | static func bar(): 6 | pass 7 | 8 | 9 | class Foo: 10 | static func foo(): 11 | pass 12 | 13 | static func bar(): 14 | pass 15 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/apos_docstring.gd: -------------------------------------------------------------------------------- 1 | # this is illegal in godot 2 | '''x 3 | ''' 4 | # but this is legal 5 | '''x''' 6 | # as this is basically '' 'x' and '' 7 | 8 | # thus we recognize '''...''' to later convert it to '...' or so 9 | xxx 10 | -------------------------------------------------------------------------------- /tests/potential-godot-bugs/match_w_multiline_list_85760.gd: -------------------------------------------------------------------------------- 1 | func foo(x): 2 | match x: 3 | 1, 2, 3: # ok 4 | pass 5 | (4, 5, 6): # parse error 6 | pass 7 | ( 8 | 7, # parse error 9 | 8, 10 | 9 11 | ): 12 | pass 13 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/node_paths.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func foo(): 4 | $Child 5 | $"path" 6 | $'path' 7 | $"""path""" 8 | $Child/Sub 9 | # @"xx" 10 | # @'xx' 11 | # @"""xxxx""" 12 | $Child/Sub.text = "xx" 13 | $/root 14 | $/root/A/B/C 15 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_326_multistatement_lambda_corner_case.in.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func _ready() -> void: 4 | get_tree().create_timer(1.0).timeout.connect( 5 | func(): 6 | print("Hello world!") 7 | print("This is a bug test.") 8 | ) 9 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/typed_dicts.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var d : Dictionary[String, int] 3 | var d2 :Dictionary[int, int] = { 1: 2 } 4 | var d3 :Dictionary[int, int] = { 1: 2,2:3,3:4,4:5,5:6,6:7,7:8,8:9,9:10,10:11,11:12,12:13,13:14,14:15,15:16 } 5 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/comments.gd: -------------------------------------------------------------------------------- 1 | # asda 2 | 3 | pass # asd 4 | 5 | func foo(): # asd 6 | pass # asd 7 | 8 | # xx 9 | 10 | 11 | # asd 12 | # asd 13 | # asd 14 | 15 | func bar(): 16 | if true: 17 | pass 18 | # 19 | pass 20 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/multiline_annotations_66322.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | @export_enum( 4 | "Aaaaaaaaaaa", 5 | "Bbbbbbbbb", 6 | "Cccccccc", 7 | "Ddddddd", 8 | "Eeeeee", 9 | "Ffffffffff", 10 | "Gggggggggg", 11 | "Hhhhhhhhh" 12 | ) 13 | var b 14 | -------------------------------------------------------------------------------- /gdtoolkit/formatter/types.py: -------------------------------------------------------------------------------- 1 | from typing import Tuple, List, Optional 2 | 3 | PreviouslyProcessedLineNumber = int 4 | FormattedLine = Tuple[Optional[int], str] 5 | FormattedLines = List[FormattedLine] 6 | Outcome = Tuple[FormattedLines, PreviouslyProcessedLineNumber] 7 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_195_dot_chain_corner_case.in.gd: -------------------------------------------------------------------------------- 1 | func _start_building_placement(building_prototype, Constants): 2 | var _active_blueprint_node = ( 3 | load(Constants.BUILDING_BLUEPRINTS[building_prototype.resource_path]) . instantiate() 4 | ) 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_195_dot_chain_corner_case.out.gd: -------------------------------------------------------------------------------- 1 | func _start_building_placement(building_prototype, Constants): 2 | var _active_blueprint_node = ( 3 | load(Constants.BUILDING_BLUEPRINTS[building_prototype.resource_path]).instantiate() 4 | ) 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/short_dict_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = {'a':1,'b':2,1:6} 4 | var y = {{'a':1,'b':2}:{1:6}} 5 | var z = { 6 | {'a': 1, 'b': 1}: {'a': 1, 'b': 1}, 7 | {'a': 1, 'b': 1}: {'a': 1, 'b': 1} 8 | } 9 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/semicolon.gd: -------------------------------------------------------------------------------- 1 | const x = 1; const y = 2 2 | const xx = 1; const yy = 2; 3 | 4 | class X: 5 | const x = 1; const y = 2 6 | const xx = 1; const yy = 2; 7 | 8 | func foo(): 9 | var xxx = 1; var yyy = 2 10 | var xxxx = 1; var yyyy = 2; 11 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/assignment_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(z): 3 | var x 4 | x = 1 5 | x += 1 6 | x **= 2 7 | z[[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]] = [ 8 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 9 | ] 10 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_classes_and_functions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | pass 3 | 4 | func foo(): 5 | pass 6 | 7 | class Y: 8 | func bar(): 9 | pass 10 | 11 | 12 | class Z: 13 | pass 14 | 15 | 16 | class Q: 17 | class W: 18 | pass 19 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_160_multiline_call_chaining.out.gd: -------------------------------------------------------------------------------- 1 | func do_some_stuff(x): 2 | return x 3 | 4 | 5 | func foo(): 6 | ( 7 | do_some_stuff(["with", "a", "decently", "long", "array", "of", "strings", "and", "other"]) 8 | . is_cool() 9 | ) 10 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/if_elif_else_comments.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | for i in [1]: 4 | if i: 5 | # aaa 6 | pass 7 | # bbb 8 | elif i: 9 | # ccc 10 | pass 11 | # ddd 12 | else: 13 | # eee 14 | pass 15 | # fff 16 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/parentheses_expressions_preservation.in.gd: -------------------------------------------------------------------------------- 1 | enum { BUTTON_WHEEL_UP, BUTTON_WHEEL_DOWN } 2 | class X: 3 | func foo(ev): 4 | var x = not (ev is InputEventMouseButton and (ev.button_index == BUTTON_WHEEL_DOWN or ev.button_index == BUTTON_WHEEL_UP)) 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/type_hints.in.gd: -------------------------------------------------------------------------------- 1 | class SubClass: 2 | enum NamedEnum { A, B, C } 3 | var a:Array[int] 4 | var b:Array[int] = [1] 5 | const C:Array[int]=[1] 6 | var e:Array[SubClass.NamedEnum] 7 | 8 | func foo(d:Array[int])->Array[int]: 9 | return [1] 10 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/blockless_func_n_func_suite.gd: -------------------------------------------------------------------------------- 1 | var a 2 | class X: 3 | func foo(): var b;var c 4 | var d 5 | class Y: 6 | func bar(): var e;var f 7 | var g 8 | func baz(): 9 | if true: var h 10 | var i 11 | while true: var j;var k 12 | var l 13 | var m 14 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/attribute_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(xxxxxxxxxxx): 3 | var x = xxxxxxxxxxx.y.z 4 | var y = xxxxxxxxxxx.yyyyyyyyyyyy.zzzzzzzzzzz.qqqqqqqqqqqqq.wwwwwwwwww.eeeeeeeeeeee.rrrrrrrrrrrrr.tttttt 5 | var z = xxxxxxxxxxx[[1,]].y.z.x[[1,]].c 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/if_elif_else_comments.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | for i in [1]: 4 | if i: 5 | # aaa 6 | pass 7 | # bbb 8 | elif i: 9 | # ccc 10 | pass 11 | # ddd 12 | else: 13 | # eee 14 | pass 15 | # fff 16 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/blockless_func_n_func_suite.in.gd: -------------------------------------------------------------------------------- 1 | var a 2 | class X: 3 | func foo(): var b;var c 4 | var d 5 | class Y: 6 | func bar(): var e;var f 7 | var g 8 | func baz(): 9 | if true: var h 10 | var i 11 | while true: var j;var k 12 | var l 13 | var m 14 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_339_multiline_lambda.in.gd: -------------------------------------------------------------------------------- 1 | func _ready(): 2 | var string_array: Array[String] 3 | var result := string_array.map(func(a): return a).filter( 4 | func(has_underscore): 5 | return (has_underscore.begins_with("a") or has_underscore.begins_with("b")) 6 | ) 7 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_205_static_func_corner_case.in.gd: -------------------------------------------------------------------------------- 1 | static func _is_agent_placement_position_valid(position, radius, existing_units, navigation_map_rid): 2 | pass 3 | 4 | func _is_agent_placement_position_valid2(position, radius, existing_units, navigation_map_riddddddd): 5 | pass 6 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/type_hints.out.gd: -------------------------------------------------------------------------------- 1 | class SubClass: 2 | enum NamedEnum { A, B, C } 3 | 4 | 5 | var a: Array[int] 6 | var b: Array[int] = [1] 7 | const C: Array[int] = [1] 8 | var e: Array[SubClass.NamedEnum] 9 | 10 | 11 | func foo(d: Array[int]) -> Array[int]: 12 | return [1] 13 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/comment_corner_cases.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | pass 4 | # aaaa # bbb 5 | 6 | func bar(): 7 | # xxx 8 | var x = '##' 9 | # yyy 10 | var y = "##" 11 | # zzz 12 | # """ ''' 13 | var z = """ 14 | #""" 15 | # qqq 16 | var w 17 | # www 18 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/comment_corner_cases.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | pass 4 | # aaaa # bbb 5 | 6 | func bar(): 7 | # xxx 8 | var x = "##" 9 | # yyy 10 | var y = "##" 11 | # zzz 12 | # """ ''' 13 | var z = """ 14 | #""" 15 | # qqq 16 | var w 17 | # www 18 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/force_multiline_array.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = [ 4 | 1, 5 | 2, 6 | 3, 7 | ] 8 | var y = [ 9 | [1, 2, 3], 10 | [4, 5, 6], 11 | ] 12 | var z = [ 13 | [1, 2, 3], 14 | [ 15 | 4, 16 | 5, 17 | 6, 18 | ] 19 | ] 20 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/power_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var a 4 | var b = 1**2 5 | var c = 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) 6 | var d = (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)**2 7 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_326_multistatement_lambda_corner_case.out.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | func _ready() -> void: 5 | ( 6 | get_tree() 7 | . create_timer(1.0) 8 | . timeout 9 | . connect( 10 | func(): 11 | print("Hello world!") 12 | print("This is a bug test.") 13 | ) 14 | ) 15 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/parentheses_expressions_preservation.out.gd: -------------------------------------------------------------------------------- 1 | enum { BUTTON_WHEEL_UP, BUTTON_WHEEL_DOWN } 2 | 3 | 4 | class X: 5 | func foo(ev): 6 | var x = not ( 7 | ev is InputEventMouseButton 8 | and (ev.button_index == BUTTON_WHEEL_DOWN or ev.button_index == BUTTON_WHEEL_UP) 9 | ) 10 | -------------------------------------------------------------------------------- /gdtoolkit/parser/comments.lark: -------------------------------------------------------------------------------- 1 | start: COMMENT* 2 | 3 | ANYTHING: /[^#"']+/ 4 | REGULAR_STRING: /("(?!"").*?(? void: 5 | pass 6 | 7 | var x: int 8 | var xx: int = 6 9 | var xxx := 7 10 | 11 | func baz(): 12 | var x: int 13 | var xx: int = 6 14 | var xxx := 7 15 | 16 | func expr(): 17 | 5 as int 18 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_375_warning_ignore_shadowed_variable.in.gd: -------------------------------------------------------------------------------- 1 | @warning_ignore("shadowed_variable") 2 | func foo(id: int, name: String) -> void: 3 | self.id = id 4 | self.name = name 5 | 6 | @warning_ignore("shadowed_variable_base_class") 7 | func bar(id: int, name: String) -> void: 8 | self.id = id 9 | self.name = name 10 | -------------------------------------------------------------------------------- /tests/gd2py/input-output-pairs/class_level_statements.out.py: -------------------------------------------------------------------------------- 1 | pass 2 | pass 3 | pass 4 | pass 5 | a = None 6 | b = 1 7 | c = None 8 | d = 1 9 | e = 1 10 | f = 1 11 | aa = None 12 | aaa = None 13 | A = 1 14 | B = 1 15 | C = 1 16 | class D: 17 | pass 18 | pass 19 | pass 20 | def foo(): 21 | pass 22 | def bar(): 23 | pass 24 | def baz(): 25 | pass 26 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_375_warning_ignore_shadowed_variable.out.gd: -------------------------------------------------------------------------------- 1 | @warning_ignore("shadowed_variable") 2 | func foo(id: int, name: String) -> void: 3 | self.id = id 4 | self.name = name 5 | 6 | 7 | @warning_ignore("shadowed_variable_base_class") 8 | func bar(id: int, name: String) -> void: 9 | self.id = id 10 | self.name = name 11 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_function_statements.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x 4 | var y = 1 5 | var z: int = 1 6 | var q: int 7 | var w := 1 8 | y = 2 9 | y += 1 10 | y += len( 11 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 12 | ) 13 | return 14 | return 1 15 | -------------------------------------------------------------------------------- /tests/invalid-gd-scripts/setget.gd: -------------------------------------------------------------------------------- 1 | var x setget sss, ggg 2 | var xx setget sss 3 | var xxx setget ,ggg 4 | var xxxx = 6 setget sss, ggg 5 | onready var y setget sss, ggg 6 | onready var yy = 7 setget sss, ggg 7 | export var z = 7 setget sss, ggg 8 | export (int) var zz setget sss, ggg 9 | 10 | func sss(v): 11 | pass 12 | 13 | func ggg(): 14 | pass 15 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/short_boolean_test_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var a = 1 > 2 4 | var c = [1, 2] in [[1, 2], [3]] 5 | var d = not not not true 6 | var e = true and true && true 7 | var f = true or true || true 8 | var g = 1 if true else 0 9 | var h = (1+1)+1 10 | var i = ! true 11 | var j=-a if true else +a 12 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_class_statements.in.gd: -------------------------------------------------------------------------------- 1 | class A: 2 | class B: 3 | pass 4 | 5 | class X: 6 | signal some 7 | signal some2() 8 | pass 9 | const a = 1 10 | const b := 2 11 | const c : int = 3 12 | var x 13 | var y = 1 14 | var z: int = 1 15 | var q: int 16 | var w := 1 17 | var xx : A.B 18 | 19 | class Y: 20 | extends X 21 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/abstract_functions.gd: -------------------------------------------------------------------------------- 1 | @abstract 2 | extends Node 3 | 4 | @abstract func foo() 5 | 6 | @abstract func bar() -> void 7 | 8 | @abstract func baz(a) -> void 9 | 10 | @abstract func bat(a: int) -> void 11 | 12 | @abstract func bak(a: int = 6) -> void 13 | 14 | @abstract func ban(a := 6) -> void 15 | 16 | @abstract 17 | func bal() -> void 18 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/short_boolean_test_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var a = 1 > 2 4 | var c = [1, 2] in [[1, 2], [3]] 5 | var d = not not not true 6 | var e = true and true && true 7 | var f = true or true || true 8 | var g = 1 if true else 0 9 | var h = (1 + 1) + 1 10 | var i = !true 11 | var j = -a if true else a 12 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_class_statements.out.gd: -------------------------------------------------------------------------------- 1 | class A: 2 | class B: 3 | pass 4 | 5 | 6 | class X: 7 | signal some 8 | signal some2 9 | pass 10 | const a = 1 11 | const b := 2 12 | const c: int = 3 13 | var x 14 | var y = 1 15 | var z: int = 1 16 | var q: int 17 | var w := 1 18 | var xx: A.B 19 | 20 | 21 | class Y: 22 | extends X 23 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_extends_statements.in.gd: -------------------------------------------------------------------------------- 1 | extends "res://dummy.gd" 2 | 3 | class C: 4 | extends "res://dummy.gd".X 5 | 6 | class D extends "res://dummy.gd".X: 7 | pass 8 | 9 | class E extends "res://dummy.gd": 10 | pass 11 | 12 | class F extends E: 13 | pass 14 | 15 | class G: 16 | class Y: 17 | pass 18 | 19 | class Z: 20 | extends G.Y 21 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_unistatement_lambdas.in.gd: -------------------------------------------------------------------------------- 1 | func foo(x): 2 | pass 3 | func bar(x,y): 4 | pass 5 | 6 | func baz(): 7 | foo(func(): pass) 8 | bar(func(): pass,func(): pass) 9 | var x1 = [func(): pass,func(): pass] 10 | var x2 = [func(): pass,func():pass,] 11 | var x3 = {'x':func(): pass,'y':func(): pass} 12 | var x4 = {'x':func(): pass,'y':func(): pass,} 13 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/typed_dicts.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var d: Dictionary[String, int] 3 | var d2: Dictionary[int, int] = {1: 2} 4 | var d3: Dictionary[int, int] = { 5 | 1: 2, 6 | 2: 3, 7 | 3: 4, 8 | 4: 5, 9 | 5: 6, 10 | 6: 7, 11 | 7: 8, 12 | 8: 9, 13 | 9: 10, 14 | 10: 11, 15 | 11: 12, 16 | 12: 13, 17 | 13: 14, 18 | 14: 15, 19 | 15: 16 20 | } 21 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/blockless_func_n_func_suite.out.gd: -------------------------------------------------------------------------------- 1 | var a 2 | 3 | 4 | class X: 5 | func foo(): 6 | var b 7 | var c 8 | 9 | 10 | var d 11 | 12 | 13 | class Y: 14 | func bar(): 15 | var e 16 | var f 17 | 18 | var g 19 | 20 | func baz(): 21 | if true: 22 | var h 23 | var i 24 | while true: 25 | var j 26 | var k 27 | var l 28 | 29 | 30 | var m 31 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_334_multiline_lambda.in.gd: -------------------------------------------------------------------------------- 1 | class WeaponSystemBullet extends Node: 2 | pass 3 | func foo(): 4 | var bullet_scene 5 | assert( 6 | (func() -> bool: 7 | var test_instance: Node = bullet_scene.instantiate() 8 | var is_needed_class: bool = test_instance is WeaponSystemBullet 9 | test_instance.free() 10 | return is_needed_class) 11 | .call() 12 | ) 13 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/array_values.gd: -------------------------------------------------------------------------------- 1 | var x = [] 2 | var xx = [1] 3 | var xxx = [1,] 4 | var xxxx = [1,2] 5 | var xxxxx = [1,2,3,] 6 | var xxxxxx = [ 7 | ] 8 | var xxxxxxx = [1 9 | , 10 | 2, 11 | ] 12 | var xxxxxxxx = [ 13 | 1, 14 | 2, 15 | 3, 16 | ] 17 | var xxxxxxxxx = [1, 18 | 2, 19 | 3,] 20 | var y = [1, 21 | 2, 22 | 3, 23 | ] 24 | var yy = [1, 25 | 2, 26 | 3 27 | ] 28 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/typed_arrays.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | class SubClass: 4 | enum NamedEnum { A, B, C } 5 | 6 | 7 | func _ready(): 8 | var r: Array[int] = [1,2,3] 9 | print([1,2.1] as Array[int]) 10 | var r2: Array[SubClass.NamedEnum] 11 | #print([1,2] is Array[int]) 12 | #print([1,2.0] is Array[int]) 13 | #var rr: Array[Array[int]] = [[1]] 14 | #var d: Dictionary[int,int] = {1:1} 15 | 16 | -------------------------------------------------------------------------------- /gdtoolkit/linter/problem_printer.py: -------------------------------------------------------------------------------- 1 | import sys 2 | from .problem import Problem 3 | 4 | 5 | def print_problem(problem: Problem, file_path: str) -> None: # TODO: colors 6 | print( 7 | "{}:{}: Error: {} ({})".format( 8 | file_path, 9 | problem.line, 10 | problem.description, 11 | problem.name, 12 | ), 13 | file=sys.stderr, 14 | ) 15 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/variadic_functions.in.gd: -------------------------------------------------------------------------------- 1 | func foo(...args): 2 | pass 3 | func bar(a,...args): 4 | pass 5 | func baz(a,...args,): 6 | pass 7 | func bat(a,...args:Array): 8 | pass 9 | func ban(a,...args:Array,): 10 | pass 11 | func bak(a,...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa:Array): 12 | pass 13 | -------------------------------------------------------------------------------- /tests/gd2py/input-output-pairs/func_level_statements.out.py: -------------------------------------------------------------------------------- 1 | def foo(): 2 | pass 3 | a = None 4 | b = 1 5 | c = None 6 | d = 1 7 | e = 1 8 | 1 9 | if 1: 10 | pass 11 | elif 1: 12 | pass 13 | else: 14 | pass 15 | while 1: 16 | break 17 | for i in 1: 18 | continue 19 | for j in 1: 20 | continue 21 | if 1: 22 | pass 23 | elif 1: 24 | pass 25 | elif 1: 26 | pass 27 | return 28 | return 1 29 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/await_expressions.in.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func coroutine(_r): 4 | await get_tree().process_frame 5 | return 1 6 | 7 | func coroutine2(): 8 | await get_tree().process_frame 9 | return get_tree().process_frame 10 | 11 | func foo(): 12 | await get_tree().process_frame 13 | var x=int(await coroutine([]) is int)+1 14 | var y = [1,await coroutine([1,2,]),] 15 | await await coroutine2() 16 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_extends_statements.out.gd: -------------------------------------------------------------------------------- 1 | extends "res://dummy.gd" 2 | 3 | 4 | class C: 5 | extends "res://dummy.gd".X 6 | 7 | 8 | class D: 9 | extends "res://dummy.gd".X 10 | pass 11 | 12 | 13 | class E: 14 | extends "res://dummy.gd" 15 | pass 16 | 17 | 18 | class F: 19 | extends E 20 | pass 21 | 22 | 23 | class G: 24 | class Y: 25 | pass 26 | 27 | 28 | class Z: 29 | extends G.Y 30 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/rstrings.out.gd: -------------------------------------------------------------------------------- 1 | var x = r"x" 2 | 3 | var x2 = r'x "' 4 | var x3 = r'x " " \'' 5 | var x4 = r"x '" 6 | var x5 = r"x ' ' \"" 7 | 8 | var x6 = r"x '" 9 | var x7 = r'x "' 10 | var x8 = r"x ' \"" 11 | 12 | var x9 = r"x" 13 | var x10 = r'x "' 14 | 15 | var x11 = r"""abc " def ' ghi""" 16 | 17 | var x12 = r"xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 18 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/type_test_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = 1 is int is bool 4 | var y = 1 is int is bool is bool is bool is bool is bool is bool is bool is bool is bool is bool is bool is bool is bool 5 | print([1,2.1] is Array[int]) 6 | var z = 1 is not int 7 | var z1 = 1 is not int is not bool is not bool is not bool is not bool is not bool is not bool is not bool is not bool is not bool 8 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/compound_function_statements.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | if true: 4 | pass 5 | pass 6 | if true: 7 | pass 8 | pass 9 | else: 10 | pass 11 | pass 12 | if true: 13 | pass 14 | pass 15 | elif true: 16 | pass 17 | pass 18 | else: 19 | pass 20 | pass 21 | while true: 22 | pass 23 | pass 24 | for i in range(10): 25 | break 26 | continue 27 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiplication_division_remainder_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = 1 * 2 / 2 % 2 4 | var y = ( 5 | 1 6 | * 2 7 | / 2 8 | % 2 9 | % 2 10 | % 2 11 | % 2 12 | % 2 13 | % 2 14 | % 2 15 | % 2 16 | % 2 17 | % 2 18 | % 2 19 | % 2 20 | % 2 21 | % 2 22 | % 2 23 | % 2 24 | % 2 25 | % 2 26 | % 2 27 | % 2 28 | ) 29 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_multistatement_lambdas.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var x1 = func(x): pass;pass 3 | var x2 = func(x: int): return 123;pass 4 | var x3 = func bar(): pass;123 5 | 6 | func baz(): 7 | var x1 = func(x): 8 | var y =x+1 9 | if y: 10 | return 1 11 | return 2 12 | var x2 = func(): 13 | if true: 14 | var x=1 15 | if x>0: 16 | return 5 17 | return 6 18 | return 7 19 | 20 | pass 21 | -------------------------------------------------------------------------------- /tests/gd2py/input-output-pairs/func_level_statements.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | pass 3 | var a 4 | var b = 1 5 | var c: int 6 | var d: int = 1 7 | var e := 1 8 | """xxx""" 9 | if 1: 10 | pass 11 | elif 1: 12 | pass 13 | else: 14 | pass 15 | while 1: 16 | break 17 | for i in 1: 18 | continue 19 | for j: int in 1: 20 | continue 21 | match 1: 22 | 1: 23 | pass 24 | 1: 25 | pass 26 | return 27 | return 1 28 | -------------------------------------------------------------------------------- /gdtoolkit/formatter/statement_utils.py: -------------------------------------------------------------------------------- 1 | from ..common.utils import get_line 2 | from ..common.types import Node 3 | from .context import Context 4 | from .types import Outcome 5 | 6 | 7 | def format_simple_statement( 8 | statement_name: str, statement: Node, context: Context 9 | ) -> Outcome: 10 | return ( 11 | [(get_line(statement), f"{context.indent_string}{statement_name}")], 12 | get_line(statement), 13 | ) 14 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/compound_function_statements.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | if true: 4 | pass 5 | pass 6 | if true: 7 | pass 8 | pass 9 | else: 10 | pass 11 | pass 12 | if true: 13 | pass 14 | pass 15 | elif true: 16 | pass 17 | pass 18 | else: 19 | pass 20 | pass 21 | while true: 22 | pass 23 | pass 24 | for i in range(10): 25 | break 26 | continue 27 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/rstrings.in.gd: -------------------------------------------------------------------------------- 1 | var x = r'x' 2 | 3 | var x2 = r'x "' 4 | var x3 = r'x " " \'' 5 | var x4 = r"x '" 6 | var x5 = r"x ' ' \"" 7 | 8 | var x6 = r'x \'' 9 | var x7 = r"x \"" 10 | var x8 = r'x \' "' 11 | 12 | var x9 = r'''x''' 13 | var x10 = r'''x "''' 14 | 15 | var x11 = r"""abc " def ' ghi""" 16 | 17 | var x12 = r'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx' 18 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_334_multiline_lambda.out.gd: -------------------------------------------------------------------------------- 1 | class WeaponSystemBullet: 2 | extends Node 3 | pass 4 | 5 | 6 | func foo(): 7 | var bullet_scene 8 | assert( 9 | ( 10 | (func() -> bool: 11 | var test_instance: Node = bullet_scene.instantiate() 12 | var is_needed_class: bool = test_instance is WeaponSystemBullet 13 | test_instance.free() 14 | return is_needed_class) 15 | . call() 16 | ) 17 | ) 18 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/test_corner_cases.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(result, end): 3 | var path: String = ( 4 | result 5 | . path 6 | . substr(0, end) 7 | . replace("res://", "") 8 | . replace("tests/", "") 9 | . replace("/", " ") 10 | . capitalize() 11 | ) 12 | 13 | 14 | class Y: 15 | extends X 16 | 17 | func bar(): 18 | pass 19 | 20 | 21 | class Z: 22 | extends X 23 | 24 | func bar(): 25 | pass 26 | -------------------------------------------------------------------------------- /.pre-commit-hooks.yaml: -------------------------------------------------------------------------------- 1 | - id: gdlint 2 | name: gdlint 3 | description: "gdlint - linter for GDScript" 4 | entry: gdlint 5 | language: python 6 | language_version: python3 7 | require_serial: true 8 | types: [gdscript] 9 | - id: gdformat 10 | name: gdformat 11 | description: "gdformat - formatter for GDScript" 12 | entry: gdformat 13 | language: python 14 | language_version: python3 15 | require_serial: true 16 | types: [gdscript] 17 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_unistatement_lambdas.out.gd: -------------------------------------------------------------------------------- 1 | func foo(x): 2 | pass 3 | 4 | 5 | func bar(x, y): 6 | pass 7 | 8 | 9 | func baz(): 10 | foo(func(): pass) 11 | bar(func(): pass, func(): pass) 12 | var x1 = [func(): pass, func(): pass] 13 | var x2 = [ 14 | func(): pass, 15 | func(): pass, 16 | ] 17 | var x3 = {"x": func(): pass, "y": func(): pass} 18 | var x4 = { 19 | "x": func(): pass, 20 | "y": func(): pass, 21 | } 22 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/attribute_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(xxxxxxxxxxx): 3 | var x = xxxxxxxxxxx.y.z 4 | var y = ( 5 | xxxxxxxxxxx 6 | . yyyyyyyyyyyy 7 | . zzzzzzzzzzz 8 | . qqqqqqqqqqqqq 9 | . wwwwwwwwww 10 | . eeeeeeeeeeee 11 | . rrrrrrrrrrrrr 12 | . tttttt 13 | ) 14 | var z = ( 15 | xxxxxxxxxxx[[ 16 | 1, 17 | ]] 18 | . y 19 | . z 20 | . x[[ 21 | 1, 22 | ]] 23 | . c 24 | ) 25 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_atom_expressions.in.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | func foo(): 3 | # TODO: consider adding fake parenthesis 4 | var cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc = ^"../Some/Stuff" 5 | var dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd = &"xxx" 6 | var cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc = %UniqueNodeName/Xyz 7 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_annotations.in.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | class_name Aclassname 3 | 4 | @export_enum("AaaaaaaaaaaBbbbbbbbbCcccccccDddddddEeeeeeFfffffffffGgggggggggHhhhhhhhhhhhhhhhhhhhhhhhhh") var c 5 | 6 | @export_enum("Aaaaaaaaaaa", "Bbbbbbbbb", "Cccccccc", "Ddddddd", "Eeeeee", "Ffffffffff", "Gggggggggg") var a 7 | 8 | @onready @export_enum("Aaaaaaaaaaa", "Bbbbbbbbb", "Cccccccc", "Ddddddd", "Eeeeee", "Ffffffffff", "Gggggggggg", "Hhhhhhhhh") var b 9 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/abstract_functions.out.gd: -------------------------------------------------------------------------------- 1 | @abstract class_name BaseClass 2 | 3 | @abstract class TestClass: 4 | @abstract func test_func() 5 | 6 | 7 | @abstract func simple_abstract() 8 | 9 | @abstract func abstract_with_params(param1: String, param2: int) 10 | 11 | @abstract func abstract_with_return_type() -> String 12 | 13 | @abstract func abstract_with_params_and_return(input: String) -> int 14 | 15 | 16 | func concrete_method(): 17 | pass 18 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_atom_expressions.out.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | func foo(): 5 | # TODO: consider adding fake parenthesis 6 | var cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc = ^"../Some/Stuff" 7 | var dddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddddd = &"xxx" 8 | var cccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccccc = %UniqueNodeName/Xyz 9 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/strings.out.gd: -------------------------------------------------------------------------------- 1 | var x = "x" 2 | 3 | var x2 = 'x "' 4 | var x3 = 'x " " \'' 5 | var x4 = "x '" 6 | var x5 = "x ' ' \"" 7 | 8 | var x6 = "x '" 9 | var x7 = 'x "' 10 | var x8 = "x ' \"" 11 | 12 | var x9 = "x" 13 | var x10 = 'x "' 14 | 15 | var x11 = """abc " def ' ghi""" 16 | 17 | "x" 18 | 19 | 'x "' 20 | 'x " " \'' 21 | "x '" 22 | "x ' ' \"" 23 | 24 | "x '" 25 | 'x "' 26 | "x ' \"" 27 | 28 | "x" 29 | 'x "' 30 | 31 | """abc " def ' ghi""" 32 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/force_multiline_dict.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = {'a': 1, 'c': 1, 'b': 1,} 4 | var y = { 5 | [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], 6 | 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 7 | } 8 | var q = {a=1,b=1,c=1,} 9 | var w = {xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx= [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1],} 10 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_annotations_w_comments.in.gd: -------------------------------------------------------------------------------- 1 | @tool # inline a 2 | # a 3 | extends Node 4 | # b 5 | # c 6 | 7 | var a 8 | 9 | # d 10 | @onready # inline b 11 | # e 12 | var b # inline c 13 | # f 14 | 15 | @onready 16 | # g 17 | @export_range(1, 100, 1, "or_greater") # inline d 18 | # h 19 | var c: int = 50 20 | # i 21 | 22 | class Foo: 23 | extends Node 24 | # j 25 | @onready var d # inline e 26 | # k 27 | @onready # inline f 28 | # l 29 | var e 30 | 31 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/subscription_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(p): 3 | var x = p[0][[1, 2, 3]] 4 | var y = p[[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]] 5 | var z = { 6 | x.yyyyyyyy.zzzzz.a: 'locked', 7 | x.yyyyyyyy.zzzzz.b: 'unlocked', 8 | x.yyyyyyyy.zzzzz.c: 'done', 9 | }[x] 10 | var a = p[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] 11 | var b = p[[1,2,3,]] 12 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/abstract_functions.in.gd: -------------------------------------------------------------------------------- 1 | @abstract 2 | class_name BaseClass 3 | 4 | @abstract 5 | class TestClass: 6 | @abstract 7 | func test_func() 8 | 9 | @abstract 10 | func simple_abstract() 11 | 12 | @abstract 13 | func abstract_with_params(param1: String, param2: int) 14 | 15 | @abstract 16 | func abstract_with_return_type() -> String 17 | 18 | @abstract 19 | func abstract_with_params_and_return(input: String) -> int 20 | 21 | func concrete_method(): 22 | pass 23 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_array_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = [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] 4 | var y = [[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]] 5 | var z = [ 6 | [[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]], 7 | [[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]] 8 | ] 9 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/regular_long_enum.in.gd: -------------------------------------------------------------------------------- 1 | enum { SOME_A, SOME_B, SOME_C, SOME_D = 789, SOME_E = 123, SOME_F, SOME_G, SOME_H, SOME_I, SOME_J = 9 } 2 | enum Named { SOME_A, SOME_B, SOME_C, SOME_D = 789, SOME_E = 123, SOME_F, SOME_G, SOME_H, SOME_I = 999 } 3 | enum { SOME_XA, SOME_XB, SOME_XC, SOME_XD = 789, SOME_XE = 123, SOME_XF, SOME_XG, SOME_XH, SOME_XI, SOME_XJ = 9 } 4 | enum NamedX { SOME_XA, SOME_XB, SOME_XC, SOME_XD = 789, SOME_XE = 123, SOME_XF, SOME_XG, SOME_XH, SOME_XI = 999 } 5 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_annotations_w_comments.out.gd: -------------------------------------------------------------------------------- 1 | @tool # inline a 2 | # a 3 | extends Node 4 | # b 5 | # c 6 | 7 | var a 8 | 9 | # d 10 | @onready # inline b 11 | # e 12 | var b # inline c 13 | # f 14 | 15 | @onready 16 | # g 17 | @export_range(1, 100, 1, "or_greater") # inline d 18 | # h 19 | var c: int = 50 20 | # i 21 | 22 | 23 | class Foo: 24 | extends Node 25 | # j 26 | @onready var d # inline e 27 | # k 28 | @onready # inline f 29 | # l 30 | var e 31 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_multistatement_lambdas.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var x1 = func(x): 3 | pass 4 | pass 5 | var x2 = func(x: int): 6 | return 123 7 | pass 8 | var x3 = func bar(): 9 | pass 10 | 123 11 | 12 | 13 | func baz(): 14 | var x1 = func(x): 15 | var y = x + 1 16 | if y: 17 | return 1 18 | return 2 19 | var x2 = func(): 20 | if true: 21 | var x = 1 22 | if x > 0: 23 | return 5 24 | return 6 25 | return 7 26 | 27 | pass 28 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/strings.in.gd: -------------------------------------------------------------------------------- 1 | var x = 'x' 2 | 3 | var x2 = 'x "' 4 | var x3 = 'x " " \'' 5 | var x4 = "x '" 6 | var x5 = "x ' ' \"" 7 | 8 | var x6 = 'x \'' 9 | var x7 = "x \"" 10 | var x8 = 'x \' "' 11 | 12 | var x9 = '''x''' 13 | var x10 = '''x "''' 14 | 15 | var x11 = """abc " def ' ghi""" 16 | 17 | 'x' 18 | 19 | 'x "' 20 | 'x " " \'' 21 | "x '" 22 | "x ' ' \"" 23 | 24 | 'x \'' 25 | "x \"" 26 | 'x \' "' 27 | 28 | '''x''' 29 | '''x "''' 30 | 31 | """abc " def ' ghi""" 32 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_attribute_expression_corner_case.in.gd: -------------------------------------------------------------------------------- 1 | func foo(x): 2 | var path: String = x.result.path.substr(0, 10).replace("res://", "").replace("tests/", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("", "").replace("/", " ").capitalize(1,2,3,4,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28) 3 | var path2 = x.aaaa.bbbb.ccccc().ddddd.eeee.ffff(1,2,3,4,6,7,8,9,10,11,12,13,14,15,16,17,18,19,20,21,22,23,24,25,26,27,28).gggg().hhhh.jjjj 4 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/blank_line_adding.in.gd: -------------------------------------------------------------------------------- 1 | var x 2 | var y 3 | func foo(): 4 | pass 5 | var q 6 | 7 | var w 8 | class X: 9 | pass 10 | func foo(): 11 | pass 12 | func bar(): 13 | pass 14 | class Y: 15 | pass 16 | # xxx 17 | func baz(): 18 | pass 19 | 20 | # yyy 21 | 22 | func bat(): 23 | pass 24 | func bar(): 25 | pass 26 | 27 | func baz(): 28 | pass 29 | 30 | # zzz 31 | 32 | func bat(): 33 | pass 34 | 35 | var a 36 | var b 37 | 38 | # qqq 39 | class C: 40 | pass 41 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/await_expressions.out.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | func coroutine(_r): 5 | await get_tree().process_frame 6 | return 1 7 | 8 | 9 | func coroutine2(): 10 | await get_tree().process_frame 11 | return get_tree().process_frame 12 | 13 | 14 | func foo(): 15 | await get_tree().process_frame 16 | var x = int(await coroutine([]) is int) + 1 17 | var y = [ 18 | 1, 19 | await coroutine( 20 | [ 21 | 1, 22 | 2, 23 | ] 24 | ), 25 | ] 26 | await await coroutine2() 27 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/bug_327_multiline_lambda.gd: -------------------------------------------------------------------------------- 1 | func foo(new_button, button_name, menu, _game_flow): 2 | new_button.pressed.connect( 3 | func() -> void: 4 | var test := "" 5 | _game_flow.ref.request_transition(menu[button_name].transition, menu[button_name].data) 6 | ) 7 | 8 | func bar(new_button, button_name, menu, _game_flow): 9 | new_button.pressed.connect( 10 | func(x=(1)) -> void: 11 | var test := "" 12 | _game_flow.ref.request_transition(menu[button_name].transition, menu[button_name].data) 13 | ) 14 | -------------------------------------------------------------------------------- /gdtoolkit/common/exceptions.py: -------------------------------------------------------------------------------- 1 | import lark.exceptions 2 | 3 | 4 | class GDToolkitError(Exception): 5 | pass 6 | 7 | 8 | def lark_unexpected_input_to_str(exception: lark.exceptions.UnexpectedInput): 9 | return str(exception).strip() 10 | 11 | 12 | def lark_unexpected_token_to_str(exception: lark.exceptions.UnexpectedToken, code: str): 13 | try: 14 | return f"{exception.get_context(code)}\n{exception}" 15 | except: # pylint: disable=bare-except # noqa: E722, B001 16 | return f"{exception}".strip() 17 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/mixed_type_case_n_test_expression.gd: -------------------------------------------------------------------------------- 1 | func foo(x): 2 | print('>>>') 3 | print(x is int) # true 4 | print(x as int) # 1 5 | print(x as int is int) # true 6 | print(x is int as bool) # true 7 | print(x is int as bool is bool) # true 8 | print(1.5 as int) # 1 9 | print(1.5 + 1.5 as int) # 3 => as < + 10 | print((true and x) is bool) # true 11 | print(true and x is bool) # false => and < is 12 | print(1.5 if true else 0 as int) # 1 => as < test_expr 13 | print('<<<') 14 | 15 | func _ready(): 16 | foo(1) 17 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_annotations.out.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Node 3 | 4 | var x 5 | 6 | @onready @export_range(1, 100, 1, "or_greater") var ranged_var: int = 50 7 | 8 | @onready() 9 | @export_range(1, 100, 1, "or_greater") 10 | var ranged_var_2_veryyyyyyy_loooong_naaaaaaaaaaaaaaaaaaaaaaaame: int = 50 11 | 12 | @onready @export_range(1, 100, 1, "or_greater") var ranged_var_3: int = 50 13 | 14 | @onready var ranged_var_4: int = 50 15 | 16 | 17 | class Foo: 18 | extends Node 19 | @onready var asd 20 | @onready var asd2 21 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/variadic_functions.out.gd: -------------------------------------------------------------------------------- 1 | func foo(...args): 2 | pass 3 | 4 | 5 | func bar(a, ...args): 6 | pass 7 | 8 | 9 | func baz( 10 | a, 11 | ...args, 12 | ): 13 | pass 14 | 15 | 16 | func bat(a, ...args: Array): 17 | pass 18 | 19 | 20 | func ban( 21 | a, 22 | ...args: Array, 23 | ): 24 | pass 25 | 26 | 27 | func bak( 28 | a, 29 | ...aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa: Array 30 | ): 31 | pass 32 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_annotations.in.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Node 3 | 4 | var x 5 | 6 | @onready 7 | 8 | @export_range(1, 100, 1, "or_greater") 9 | 10 | var ranged_var: int = 50 11 | 12 | @onready() @export_range(1, 100, 1, "or_greater") var ranged_var_2_veryyyyyyy_loooong_naaaaaaaaaaaaaaaaaaaaaaaame: int = 50 13 | 14 | @onready @export_range(1, 100, 1, "or_greater") 15 | var ranged_var_3: int = 50 16 | 17 | @onready var ranged_var_4: int = 50 18 | 19 | class Foo: 20 | extends Node 21 | @onready var asd 22 | @onready var asd2 23 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/dict_values.gd: -------------------------------------------------------------------------------- 1 | var x = {} 2 | var xx = {'x':1} 3 | var xxx = {'x':1,} 4 | var xxxx = {'x':1,'y':2} 5 | var xxxxx = {'x':1,'y':2,} 6 | var y = { 7 | } 8 | var yy = { 9 | 1: 2, 10 | 2: 5, 11 | } 12 | var yyy = {1:2, 13 | 2:3, 14 | } 15 | var yyyy = { 16 | 1: 17 | 2, 18 | 2: 3, 19 | } 20 | var z = { 21 | q = 5, 22 | w = 7, 23 | } 24 | var qq = { 1+2: 1 } 25 | # var mixed = { 1 : 2, 2 = 3 } # illegal 26 | # var mixed = { 1 = 2, 2 : 3 } # illegal 27 | # var mixed = {x = 2, 'y': 1} # illegal 28 | # var mixed2 = {'y': 1, x = 2} # illegal 29 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_annotations.out.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | class_name Aclassname 3 | 4 | @export_enum( 5 | "AaaaaaaaaaaBbbbbbbbbCcccccccDddddddEeeeeeFfffffffffGgggggggggHhhhhhhhhhhhhhhhhhhhhhhhhh" 6 | ) 7 | var c 8 | 9 | @export_enum( 10 | "Aaaaaaaaaaa", "Bbbbbbbbb", "Cccccccc", "Ddddddd", "Eeeeee", "Ffffffffff", "Gggggggggg" 11 | ) 12 | var a 13 | 14 | @onready 15 | @export_enum( 16 | "Aaaaaaaaaaa", 17 | "Bbbbbbbbb", 18 | "Cccccccc", 19 | "Ddddddd", 20 | "Eeeeee", 21 | "Ffffffffff", 22 | "Gggggggggg", 23 | "Hhhhhhhhh" 24 | ) 25 | var b 26 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_function_definitions.in.gd: -------------------------------------------------------------------------------- 1 | class Y: 2 | func _init(a, b, c): 3 | pass 4 | 5 | class X: 6 | extends Y 7 | func foo(a): 8 | pass 9 | 10 | func bar(a,b): 11 | pass 12 | 13 | func baz (a, b=1): 14 | pass 15 | 16 | func bax (a, b:=1): 17 | pass 18 | 19 | func bac (a, b:int): 20 | pass 21 | 22 | func bav (a, b:int=1): 23 | pass 24 | 25 | func bab (a, b:int=1,c:=1) -> int: 26 | return 1 27 | 28 | func ban (a,b,c,): 29 | pass 30 | 31 | class Z: 32 | extends Y 33 | func _init (a,b:=1,c:int=1): 34 | pass 35 | -------------------------------------------------------------------------------- /tests/conftest.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from gdtoolkit.parser import parser 4 | 5 | 6 | def pytest_configure(config): 7 | config.addinivalue_line( 8 | "markers", "godot_check_only: testcase uses headless godot w/ --check-only" 9 | ) 10 | config.addinivalue_line( 11 | "markers", "generated: testcases w/ content generated by hypothesis" 12 | ) 13 | config.addinivalue_line("markers", "parser: parser testcases") 14 | 15 | 16 | @pytest.fixture(scope="session", autouse=True) 17 | def disable_parser_caching(): 18 | parser.disable_grammar_caching() 19 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/array_n_dict_expression_comments.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = [ # a 4 | 1, # b 5 | 2, # c 6 | ] # d 7 | var y = { # q 8 | 'x': 1, # w 9 | 'y': 2, # e 10 | } # r 11 | var sut 12 | var Config 13 | sut.init(self, { 14 | 0: 'x', 15 | 1: 'y', 16 | 2: 'z', 17 | }, { 18 | Config.Household.LevelingDirection.POSITIVE: 0.1, # 10%/s 19 | Config.Household.LevelingDirection.NEGATIVE: 0.1, 20 | }) 21 | sut.process(10.0, 0) # 0.0 22 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/array_n_dict_expression_comments.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = [ # a 4 | 1, # b 5 | 2, # c 6 | ] # d 7 | var y = { # q 8 | "x": 1, # w 9 | "y": 2, # e 10 | } # r 11 | var sut 12 | var Config 13 | ( 14 | sut 15 | . init( 16 | self, 17 | { 18 | 0: "x", 19 | 1: "y", 20 | 2: "z", 21 | }, 22 | { 23 | Config.Household.LevelingDirection.POSITIVE: 0.1, # 10%/s 24 | Config.Household.LevelingDirection.NEGATIVE: 0.1, 25 | } 26 | ) 27 | ) 28 | sut.process(10.0, 0) # 0.0 29 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/force_multiline_dict.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = { 4 | "a": 1, 5 | "c": 1, 6 | "b": 1, 7 | } 8 | var y = { 9 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]: 10 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 11 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx": 12 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 13 | } 14 | var q = { 15 | a = 1, 16 | b = 1, 17 | c = 1, 18 | } 19 | var w = { 20 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx = 21 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 22 | } 23 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/blank_line_adding.out.gd: -------------------------------------------------------------------------------- 1 | var x 2 | var y 3 | 4 | 5 | func foo(): 6 | pass 7 | 8 | 9 | var q 10 | 11 | var w 12 | 13 | 14 | class X: 15 | pass 16 | 17 | func foo(): 18 | pass 19 | 20 | func bar(): 21 | pass 22 | 23 | class Y: 24 | pass 25 | 26 | # xxx 27 | func baz(): 28 | pass 29 | 30 | # yyy 31 | 32 | func bat(): 33 | pass 34 | 35 | 36 | func bar(): 37 | pass 38 | 39 | 40 | func baz(): 41 | pass 42 | 43 | 44 | # zzz 45 | 46 | 47 | func bat(): 48 | pass 49 | 50 | 51 | var a 52 | var b 53 | 54 | 55 | # qqq 56 | class C: 57 | pass 58 | -------------------------------------------------------------------------------- /tests/linter/test_basic_corner_cases.py: -------------------------------------------------------------------------------- 1 | from gdtoolkit.linter import lint_code 2 | 3 | 4 | def test_empty_code_linting(): 5 | lint_code("") 6 | 7 | 8 | def test_newlineless_code(): 9 | code = """func foo(): 10 | pass""" 11 | lint_code(code) 12 | 13 | 14 | def test_docstring(): 15 | code = '"""\nhello world!\n"""' 16 | lint_code(code) 17 | 18 | 19 | def test_trailing_comma_in_params_list(): 20 | code = """static func _is_agent_placement_position_valid( 21 | position, 22 | radius, 23 | existing_units, 24 | navigation_map_rid,):pass""" 25 | lint_code(code) 26 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_arithmetic_expression.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = ( 4 | 1 5 | + 1 6 | + 1 7 | + 1 8 | + 1 9 | + 1 10 | + 1 11 | - 1 12 | + 1 13 | + 1 14 | + 1 15 | + 1 16 | + 1 17 | + 1 18 | + 1 19 | + 1 20 | + 1 21 | + 1 22 | + 1 23 | - 1 24 | + 1 25 | + 1 26 | + 1 27 | + 1 28 | + 1 29 | + 1 30 | + 1 31 | + 1 32 | + 1 33 | + 1 34 | + 1 35 | + 1 36 | + 1 37 | + 1 38 | + 1 39 | + 1 40 | + 1 41 | + 1 42 | + 1 43 | + 1 44 | + 1 45 | + 1 46 | + 1 47 | ) 48 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_dict_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = {'a': 1, 'b': 1, 'c': 1, 'd': 1, 'e': 1, 'f': 1, 'g': 1, 'h': 1, 'i': 1, 'j': 1, 'k': 1} 4 | var y = { 5 | [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], 6 | [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,1], 7 | } 8 | var z = { 9 | 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 10 | 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy': [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 11 | } 12 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/or_xor_and_shift_bitwise_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var a = 1 << 2 >> 3 4 | var b = 1 & 1 & 1 5 | var c = 1 ^ 1 ^ 1 6 | var d = 1 | 1 | 1 7 | var q = 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 << 1 8 | var w = 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 & 1 9 | var e = 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 ^ 1 10 | var r = 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 | 1 11 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_array_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = [ 4 | 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 5 | ] 6 | var y = [ 7 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 8 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 9 | ] 10 | var z = [ 11 | [ 12 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 13 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 14 | ], 15 | [ 16 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 17 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 18 | ] 19 | ] 20 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_properties.in.gd: -------------------------------------------------------------------------------- 1 | var p1: 2 | set = __set 3 | var p2: 4 | set = __set, 5 | get = __get 6 | var p3: 7 | get = __get 8 | var p4: 9 | get = __get, 10 | set = __set 11 | 12 | var p5: 13 | get: pass 14 | var p6: 15 | get: 16 | pass 17 | var p7: 18 | set(_x): pass 19 | var p8: 20 | set(_x): 21 | pass 22 | 23 | var p9: 24 | set(_x): pass 25 | get: return 1 26 | var p9x: 27 | get(): return 1 28 | var p10: 29 | get: 30 | var xyz = 123 31 | return xyz 32 | set(x): 33 | var xyz = 234 34 | p8 = x + 1 + xyz 35 | 36 | func __get(): 37 | return 1 38 | 39 | func __set(v): 40 | pass 41 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/regular_long_enum.out.gd: -------------------------------------------------------------------------------- 1 | enum { 2 | SOME_A, SOME_B, SOME_C, SOME_D = 789, SOME_E = 123, SOME_F, SOME_G, SOME_H, SOME_I, SOME_J = 9 3 | } 4 | enum Named { 5 | SOME_A, SOME_B, SOME_C, SOME_D = 789, SOME_E = 123, SOME_F, SOME_G, SOME_H, SOME_I = 999 6 | } 7 | enum { 8 | SOME_XA, 9 | SOME_XB, 10 | SOME_XC, 11 | SOME_XD = 789, 12 | SOME_XE = 123, 13 | SOME_XF, 14 | SOME_XG, 15 | SOME_XH, 16 | SOME_XI, 17 | SOME_XJ = 9 18 | } 19 | enum NamedX { 20 | SOME_XA, 21 | SOME_XB, 22 | SOME_XC, 23 | SOME_XD = 789, 24 | SOME_XE = 123, 25 | SOME_XF, 26 | SOME_XG, 27 | SOME_XH, 28 | SOME_XI = 999 29 | } 30 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_function_definitions.out.gd: -------------------------------------------------------------------------------- 1 | class Y: 2 | func _init(a, b, c): 3 | pass 4 | 5 | 6 | class X: 7 | extends Y 8 | 9 | func foo(a): 10 | pass 11 | 12 | func bar(a, b): 13 | pass 14 | 15 | func baz(a, b = 1): 16 | pass 17 | 18 | func bax(a, b := 1): 19 | pass 20 | 21 | func bac(a, b: int): 22 | pass 23 | 24 | func bav(a, b: int = 1): 25 | pass 26 | 27 | func bab(a, b: int = 1, c := 1) -> int: 28 | return 1 29 | 30 | func ban( 31 | a, 32 | b, 33 | c, 34 | ): 35 | pass 36 | 37 | 38 | class Z: 39 | extends Y 40 | 41 | func _init(a, b := 1, c: int = 1): 42 | pass 43 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_326_multistatement_lambda_corner_case_workaround.in.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func _ready() -> void: 4 | get_tree().create_timer(1.0).timeout.connect( 5 | func(): 6 | print("Hello world!") 7 | print("This is a bug test.") 8 | ) 9 | func foo(): 10 | get_tree().create_timer(1.0).timeout.connect( 11 | func(): 12 | print("Hello world!") 13 | return [1,] 14 | ) 15 | func bar(): 16 | get_tree().create_timer(1.0).timeout.connect(func(): return [1,]) 17 | func baz(x): 18 | x.aaaaaaaaaaaaa.bbbbbbbbbbbb.cccccccccccccc.dddddddddddddd.eeeeeeeeeeeeee.fffffffffffff.ggggggggggggg.hhhhh(func(): return 1) 19 | -------------------------------------------------------------------------------- /tests/gd2py/input-output-pairs/class_level_statements.in.gd: -------------------------------------------------------------------------------- 1 | # misc 2 | @tool 3 | extends Node 4 | class_name ClassName 5 | signal signal_name 6 | pass 7 | 8 | # variables 9 | var a 10 | var b = 1 11 | var c: int 12 | var d: int = 1 13 | var e := 1 14 | var f = 1 # TODO: puppet 15 | @export(float) var aa 16 | @onready var aaa 17 | 18 | # constants 19 | const A = 1 20 | const B: int = 1 21 | const C := 1 22 | 23 | # compounds 24 | class D: 25 | pass 26 | 27 | 28 | enum { AAA, BBB } 29 | enum Named { AAA, BBB } 30 | 31 | 32 | func foo(): 33 | pass 34 | 35 | 36 | static func bar(): 37 | pass 38 | 39 | 40 | func baz(a,b,...c): 41 | pass 42 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/parentheses_expressions_removal.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(p): 3 | var x = (((1))) 4 | var y = foo((1)) 5 | var z = foo(("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")) 6 | var a = [(1),2] 7 | var b = {(1):(2)} 8 | var c = [("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"),"x"] 9 | var d = {("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"):("xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx")} 10 | var e = a[(1)] 11 | 12 | func bar(x = (1), y := (1)): 13 | pass 14 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/enums.gd: -------------------------------------------------------------------------------- 1 | enum {AA, BB, CC } 2 | enum {XX, YY, ZZ, } 3 | enum {A, 4 | B, 5 | C} 6 | enum { 7 | X,Y, 8 | Z 9 | } 10 | 11 | enum AAAAA {AA, BB, CC } 12 | enum BBBBBB {XX, YY, ZZ, } 13 | enum cc {A, 14 | B, 15 | C} 16 | enum _dddd{ 17 | X,Y, 18 | Z 19 | } 20 | 21 | class Household: 22 | enum LevelingDirection { POSITIVE, NEGATIVE, NEGATIVE_FAST } 23 | 24 | enum {TILE_BRICK, TILE_FLOOR, TILE_SPIKE, TILE_TELEPORT} 25 | 26 | enum State {STATE_IDLE, STATE_JUMP = 5, STATE_SHOOT} 27 | 28 | enum {} 29 | 30 | enum Name {} 31 | 32 | enum WithNegativeElement { POS, NEG = -1 } 33 | 34 | enum WithOperator { ADD = 1 + 3, SHIFT = 1<<2 } 35 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_signal_statements.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | signal a(x, y) 3 | signal b(aaaaaaaa, bbbbbbbbb, ccccccccc, dddddddd, eeeeeeee, ffffffff, ggggggggg, hhhhhhhh, iiiiiiii, jjjjjjjjjjj) 4 | signal c(x, y,) 5 | signal d(x:int,) 6 | signal e(x,y:float) 7 | signal f(x:int,aaaaaaaa, bbbbbbbbb, ccccccccc, dddddddd, eeeeeeee, ffffffff, ggggggggg, hhhhhhhh, iiiiiiii, jjjjjjjjjjj,y:float) 8 | signal g(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: int) 9 | signal h(xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx) 10 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/type_test_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = 1 is int is bool 4 | var y = ( 5 | 1 6 | is int 7 | is bool 8 | is bool 9 | is bool 10 | is bool 11 | is bool 12 | is bool 13 | is bool 14 | is bool 15 | is bool 16 | is bool 17 | is bool 18 | is bool 19 | is bool 20 | ) 21 | print([1, 2.1] is Array[int]) 22 | var z = 1 is not int 23 | var z1 = ( 24 | 1 25 | is not int 26 | is not bool 27 | is not bool 28 | is not bool 29 | is not bool 30 | is not bool 31 | is not bool 32 | is not bool 33 | is not bool 34 | is not bool 35 | ) 36 | -------------------------------------------------------------------------------- /tests/common.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | 4 | GODOT_SERVER = "godot4.5" 5 | 6 | 7 | def write_file(a_dir, file_name, code): 8 | file_path = os.path.join(a_dir, file_name) 9 | with open(file_path, "w", encoding="utf-8") as handle: 10 | handle.write(code) 11 | return file_path 12 | 13 | 14 | def write_project_settings(a_dir): 15 | write_file( 16 | a_dir, 17 | "project.godot", 18 | """[debug] 19 | gdscript/warnings/inference_on_variant=1 20 | gdscript/warnings/native_method_override=1 21 | gdscript/warnings/get_node_default_without_onready=1 22 | gdscript/warnings/onready_with_export=1 23 | """, 24 | ) 25 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_atom_expressions.in.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func foo(): 4 | var x=1 5 | var y = x 6 | var z = 0x99ff 7 | var q = null 8 | var w = 'xxx' 9 | var r = """asd""" 10 | var t = $Some/Path 11 | var k = $"../Some/Stuff" 12 | var l = 0xfF9900 13 | var m = -0xfF9900 14 | var b = 0b001101 15 | var c = -0b001101 16 | var v=+1 17 | var n=+x 18 | var d = ^"../Some/Stuff" 19 | var e = &"xxx" 20 | var xa=$%UniqueNodeName 21 | var xb=$%UniqueNodeName/Xyz 22 | var xc=%UniqueNodeName 23 | var xd=%UniqueNodeName/Xyz 24 | var xe=%"a/b/c" 25 | var xf=%UniqueNodeName/%AnotherUniqueNodeName 26 | var xg=$/root 27 | var xh=$/root/a/b/c 28 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_properties.out.gd: -------------------------------------------------------------------------------- 1 | var p1: 2 | set = __set 3 | var p2: 4 | set = __set, 5 | get = __get 6 | var p3: 7 | get = __get 8 | var p4: 9 | get = __get, 10 | set = __set 11 | 12 | var p5: 13 | get: 14 | pass 15 | var p6: 16 | get: 17 | pass 18 | var p7: 19 | set(_x): 20 | pass 21 | var p8: 22 | set(_x): 23 | pass 24 | 25 | var p9: 26 | set(_x): 27 | pass 28 | get: 29 | return 1 30 | var p9x: 31 | get(): 32 | return 1 33 | var p10: 34 | get: 35 | var xyz = 123 36 | return xyz 37 | set(x): 38 | var xyz = 234 39 | p8 = x + 1 + xyz 40 | 41 | 42 | func __get(): 43 | return 1 44 | 45 | 46 | func __set(v): 47 | pass 48 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/parentheses_expressions_removal.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(p): 3 | var x = 1 4 | var y = foo(1) 5 | var z = foo( 6 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 7 | ) 8 | var a = [1, 2] 9 | var b = {1: 2} 10 | var c = [ 11 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx", "x" 12 | ] 13 | var d = { 14 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx": 15 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 16 | } 17 | var e = a[1] 18 | 19 | func bar(x = 1, y := 1): 20 | pass 21 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/functions.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | pass 3 | 4 | enum { xxx } 5 | 6 | var glob 7 | 8 | func bar(): 9 | var x 10 | var y = 5 11 | xxx 12 | breakpoint 13 | if true: 14 | pass 15 | pass 16 | if true: 17 | pass 18 | else: 19 | pass 20 | pass 21 | if true: 22 | pass 23 | elif false: 24 | pass 25 | pass 26 | while true: 27 | pass 28 | var arr 29 | for i in arr: 30 | pass 31 | 32 | static func asd(): 33 | pass 34 | 35 | func ret(): 36 | return 37 | 38 | func ret2(): 39 | return 1 40 | 41 | func set_glob(g): 42 | glob = g 43 | 44 | func fun(a,b): 45 | pass 46 | 47 | func long(): 48 | pass 49 | 50 | pass 51 | pass 52 | 53 | pass 54 | 55 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_trailing_comma_scenarios.in.gd: -------------------------------------------------------------------------------- 1 | enum RoadTiles { DEAD_END, STRAIGHT, TURN, T_INTERSECTION, FULL_INTERSECTION } 2 | 3 | const TRANSITION_MAP = { 4 | RoadTiles.DEAD_END: [ 5 | [1.0, RoadTiles.STRAIGHT], 6 | ], 7 | RoadTiles.STRAIGHT: [ 8 | [0.94, RoadTiles.STRAIGHT], 9 | [0.03, RoadTiles.FULL_INTERSECTION], 10 | [0.01, RoadTiles.T_INTERSECTION], 11 | [0.01, RoadTiles.TURN], 12 | [0.01, RoadTiles.DEAD_END], 13 | ], 14 | RoadTiles.TURN: [ 15 | [1.0, RoadTiles.STRAIGHT], 16 | ], 17 | RoadTiles.T_INTERSECTION: [ 18 | [1.0, RoadTiles.STRAIGHT], 19 | ], 20 | RoadTiles.FULL_INTERSECTION: [ 21 | [1.0, RoadTiles.STRAIGHT], 22 | ], 23 | } 24 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/call_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class Y: 2 | func f(a0,a1,a2,a3,a4,a5,a6,a7,a8,a9,a10,a11,a12,a13,a14,a15,a16,a17,a18,a19,a20,a21,a22,a23,a24,a25,a26,a27,a28): 3 | pass 4 | 5 | func g(): 6 | pass 7 | 8 | class X: 9 | extends Y 10 | 11 | func bar(): 12 | pass 13 | 14 | func foo(a): 15 | var x = bar() 16 | var z = a.b.c(1, 2) 17 | var zz = a.b.c(1, 2,) 18 | var q = f(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) 19 | var qq = f(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,) 20 | var e = a.f(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) 21 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enum_comments.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | enum First { A, B } # xxx 3 | enum Second { A, B } # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 4 | enum Third { # aaa 5 | A # bbb 6 | } 7 | enum Fourth { # aaa 8 | A, # bbb 9 | B, # ccc 10 | } # ddd 11 | enum Fifth { # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 12 | A # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 13 | } # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 14 | enum Sixth { A, B, } # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 15 | enum Seventh { # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 16 | A, # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 17 | } # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 18 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/enum_comments.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | enum First { A, B } # xxx 3 | enum Second { A, B } # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 4 | enum Third { A } # aaa # bbb 5 | enum Fourth { # aaa 6 | A, # bbb 7 | B, # ccc 8 | } # ddd 9 | enum Fifth { A } # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 10 | enum Sixth { 11 | A, 12 | B, 13 | } # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 14 | enum Seventh { # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 15 | A, # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 16 | } # xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 17 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_atom_expressions.out.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | func foo(): 5 | var x = 1 6 | var y = x 7 | var z = 0x99ff 8 | var q = null 9 | var w = "xxx" 10 | var r = """asd""" 11 | var t = $Some/Path 12 | var k = $"../Some/Stuff" 13 | var l = 0xfF9900 14 | var m = -0xfF9900 15 | var b = 0b001101 16 | var c = -0b001101 17 | var v = +1 18 | var n = x 19 | var d = ^"../Some/Stuff" 20 | var e = &"xxx" 21 | var xa = $%UniqueNodeName 22 | var xb = $%UniqueNodeName/Xyz 23 | var xc = %UniqueNodeName 24 | var xd = %UniqueNodeName/Xyz 25 | var xe = %"a/b/c" 26 | var xf = %UniqueNodeName/%AnotherUniqueNodeName 27 | var xg = $/root 28 | var xh = $/root/a/b/c 29 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/addition_n_subtraction_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = 1 + 1 4 | var y = 1 - 1 5 | var q = ( 6 | 1 7 | + 1 8 | + 1 9 | + 1 10 | + 1 11 | + 1 12 | + 1 13 | + 1 14 | + 1 15 | + 1 16 | + 1 17 | + 1 18 | + 1 19 | + 1 20 | + 1 21 | + 1 22 | + 1 23 | + 1 24 | + 1 25 | + 1 26 | + 1 27 | + 1 28 | + 1 29 | ) 30 | var w = ( 31 | 1 32 | - 1 33 | - 1 34 | - 1 35 | - 1 36 | - 1 37 | - 1 38 | - 1 39 | - 1 40 | - 1 41 | - 1 42 | - 1 43 | - 1 44 | - 1 45 | - 1 46 | - 1 47 | - 1 48 | - 1 49 | - 1 50 | - 1 51 | - 1 52 | - 1 53 | - 1 54 | ) 55 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_trailing_comma_scenarios.out.gd: -------------------------------------------------------------------------------- 1 | enum RoadTiles { DEAD_END, STRAIGHT, TURN, T_INTERSECTION, FULL_INTERSECTION } 2 | 3 | const TRANSITION_MAP = { 4 | RoadTiles.DEAD_END: 5 | [ 6 | [1.0, RoadTiles.STRAIGHT], 7 | ], 8 | RoadTiles.STRAIGHT: 9 | [ 10 | [0.94, RoadTiles.STRAIGHT], 11 | [0.03, RoadTiles.FULL_INTERSECTION], 12 | [0.01, RoadTiles.T_INTERSECTION], 13 | [0.01, RoadTiles.TURN], 14 | [0.01, RoadTiles.DEAD_END], 15 | ], 16 | RoadTiles.TURN: 17 | [ 18 | [1.0, RoadTiles.STRAIGHT], 19 | ], 20 | RoadTiles.T_INTERSECTION: 21 | [ 22 | [1.0, RoadTiles.STRAIGHT], 23 | ], 24 | RoadTiles.FULL_INTERSECTION: 25 | [ 26 | [1.0, RoadTiles.STRAIGHT], 27 | ], 28 | } 29 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_multistatement_lambdas.in.gd: -------------------------------------------------------------------------------- 1 | func xyz(x): 2 | pass 3 | func foo(): 4 | 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: 5 | 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] 6 | var b = len(a) + 1 7 | if a > 1: 8 | return 1 9 | return 2 10 | 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): 11 | 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} 12 | var b = [a['a1'],1,2,3] 13 | for bb in b: 14 | break 15 | 16 | pass 17 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/standalone_comments_in_expressions.in.gd: -------------------------------------------------------------------------------- 1 | signal s( 2 | # qq1 3 | a, 4 | # ww1 5 | b 6 | # ee1 7 | ) 8 | # TODO: change to annotation 9 | # export( 10 | # # qq2 11 | # int, 12 | # # ww2 13 | # 20 14 | # # ee2 15 | # ) var x 16 | 17 | func foo(): 18 | # aaa 19 | var x = [1,2 # bbb 20 | # ccc 21 | ] 22 | # ddd 23 | var y = [ 24 | # xxx 25 | 1,2,3,[ 26 | # yyy1 27 | 1,], 28 | # yyy2 29 | 4, 30 | # zzz 31 | ] 32 | var z = { 33 | # qq3 34 | 1: 2, 35 | # ww3 36 | } 37 | 38 | 39 | func bar( 40 | # qq4 41 | a, 42 | # ww4 43 | b 44 | # ee4 45 | ): 46 | # rr4 47 | pass 48 | 49 | func baz(): 50 | bar( 51 | # qq5 52 | 1, 53 | # ww5 54 | 2 55 | # ee5 56 | ) 57 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/bug_326_multistatement_lambda_corner_case_workaround.out.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | 4 | func _ready() -> void: 5 | get_tree().create_timer(1.0).timeout.connect( 6 | func(): 7 | print("Hello world!") 8 | print("This is a bug test.") 9 | ) 10 | 11 | 12 | func foo(): 13 | get_tree().create_timer(1.0).timeout.connect( 14 | func(): 15 | print("Hello world!") 16 | return [ 17 | 1, 18 | ] 19 | ) 20 | 21 | 22 | func bar(): 23 | get_tree().create_timer(1.0).timeout.connect( 24 | func(): 25 | return [ 26 | 1, 27 | ] 28 | ) 29 | 30 | 31 | func baz(x): 32 | x.aaaaaaaaaaaaa.bbbbbbbbbbbb.cccccccccccccc.dddddddddddddd.eeeeeeeeeeeeee.fffffffffffff.ggggggggggggg.hhhhh( 33 | func(): return 1 34 | ) 35 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_annotations_w_comments.in.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | class_name Aclassname 3 | # a 4 | @export_group( # inline a 5 | "res://aaaaaaaaaaaaa/bbbbbbbbbbbbbbb/cccccccccccc/ddddddddddd/eeeeeeeeeeeeeee/ffffffffff.tres" # inline b 6 | ) # inline c 7 | # b 8 | 9 | # c 10 | @export_enum( # inline d 11 | "Aaaaaaaaaaa", "Bbbbbbbbb", "Cccccccc", "Ddddddd", "Eeeeee", "Ffffffffff", "Gggggggggg" # inline e 12 | ) # inline f 13 | # d 14 | var a # inline g 15 | # e 16 | 17 | # f 18 | # @onready 19 | # g 20 | @export_enum( # inline h 21 | "Aaaaaaaaaaa", # inline i 22 | "Bbbbbbbbb", 23 | "Cccccccc", # inline j 24 | "Ddddddd", 25 | "Eeeeee", 26 | "Ffffffffff", 27 | "Gggggggggg", 28 | "Hhhhhhhhh" 29 | ) # inline k 30 | # h 31 | var b 32 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_annotations_w_comments.out.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | class_name Aclassname 3 | # a 4 | @export_group( 5 | "res://aaaaaaaaaaaaa/bbbbbbbbbbbbbbb/cccccccccccc/ddddddddddd/eeeeeeeeeeeeeee/ffffffffff.tres" # inline a # inline b 6 | ) # inline c 7 | # b 8 | 9 | # c 10 | @export_enum( 11 | "Aaaaaaaaaaa", "Bbbbbbbbb", "Cccccccc", "Ddddddd", "Eeeeee", "Ffffffffff", "Gggggggggg" # inline d # inline e 12 | ) # inline f 13 | # d 14 | var a # inline g 15 | # e 16 | 17 | # f 18 | # @onready 19 | # g 20 | @export_enum( # inline h 21 | "Aaaaaaaaaaa", # inline i 22 | "Bbbbbbbbb", 23 | "Cccccccc", # inline j 24 | "Ddddddd", 25 | "Eeeeee", 26 | "Ffffffffff", 27 | "Gggggggggg", 28 | "Hhhhhhhhh" 29 | ) # inline k 30 | # h 31 | var b 32 | -------------------------------------------------------------------------------- /tests/linter/test_linter.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from gdtoolkit.linter import lint_code 4 | 5 | DATA_DIR = "../valid-gd-scripts" 6 | 7 | 8 | def pytest_generate_tests(metafunc): 9 | this_directory = os.path.dirname(os.path.abspath(__file__)) 10 | if "gdscript_file_path" in metafunc.fixturenames: 11 | directory_tests = os.path.join(this_directory, DATA_DIR) 12 | metafunc.parametrize( 13 | "gdscript_file_path", 14 | [os.path.join(directory_tests, f) for f in os.listdir(directory_tests)], 15 | ) 16 | 17 | 18 | def test_linting_success(gdscript_file_path): 19 | with open(gdscript_file_path, "r", encoding="utf-8") as handle: 20 | code = handle.read() 21 | lint_code(code) # just checking if not throwing 22 | -------------------------------------------------------------------------------- /tests/gd2py/test_python_files_compilation.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | DATA_DIR = "./input-output-pairs" 4 | 5 | 6 | def pytest_generate_tests(metafunc): 7 | this_directory = os.path.dirname(os.path.abspath(__file__)) 8 | if "python_file" in metafunc.fixturenames: 9 | data_dir = os.path.join(this_directory, DATA_DIR) 10 | metafunc.parametrize( 11 | "python_file", set(f for f in os.listdir(data_dir) if f.endswith(".py")) 12 | ) 13 | 14 | 15 | def test_compilation(python_file): 16 | this_dir = os.path.dirname(os.path.abspath(__file__)) 17 | python_file_path = os.path.join(this_dir, DATA_DIR, python_file) 18 | with open(python_file_path, "r", encoding="utf-8") as handle: 19 | compile(handle.read(), filename="", mode="exec") 20 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/function_annotations.gd: -------------------------------------------------------------------------------- 1 | func a(): 2 | @warning_ignore("unused_variable") 3 | var x: Array[int] = [ 1, 2, ] 4 | 5 | func b(): 6 | @warning_ignore("unused_variable") var x: Array[int] = [ 1, 2, ] 7 | 8 | func d(): 9 | @warning_ignore("unused_variable") @warning_ignore("unused_variable") var x: Array[int] = [ 1, 2, ] 10 | 11 | func e(): 12 | @warning_ignore("unused_variable") 13 | @warning_ignore("unused_variable") 14 | var x: Array[int] = [ 1, 2, ] 15 | 16 | func f(): 17 | if true: 18 | @warning_ignore("unused_variable") 19 | @warning_ignore("unused_variable") 20 | var x: Array[int] = [ 1, 2, ] 21 | 22 | func g(): 23 | pass 24 | @warning_ignore("unused_variable") 25 | 26 | func h(): 27 | if true: 28 | @warning_ignore("unused_variable") 29 | pass 30 | -------------------------------------------------------------------------------- /.github/workflows/tests.yml: -------------------------------------------------------------------------------- 1 | name: Tests 2 | 3 | on: [push, pull_request] 4 | 5 | jobs: 6 | build: 7 | runs-on: ${{ matrix.os }} 8 | 9 | strategy: 10 | fail-fast: false 11 | matrix: 12 | python-version: [3.9, '3.10', '3.11', '3.12'] 13 | os: [ubuntu-latest, windows-latest, macos-latest] 14 | 15 | steps: 16 | - name: Checkout repository 17 | uses: actions/checkout@v4 18 | 19 | - name: Set up Python ${{ matrix.python-version }} on ${{ matrix.os }} 20 | uses: actions/setup-python@v5 21 | with: 22 | python-version: ${{ matrix.python-version }} 23 | 24 | - name: Install dependencies 25 | run: python -m pip install --upgrade setuptools pip wheel tox 26 | 27 | - name: Run tox 28 | run: tox 29 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/standalone_comments_in_expressions.out.gd: -------------------------------------------------------------------------------- 1 | signal s( 2 | # qq1 3 | a, 4 | # ww1 5 | b 6 | # ee1 7 | ) 8 | # TODO: change to annotation 9 | # export( 10 | # # qq2 11 | # int, 12 | # # ww2 13 | # 20 14 | # # ee2 15 | # ) var x 16 | 17 | 18 | func foo(): 19 | # aaa 20 | var x = [ 21 | 1, 22 | 2 # bbb 23 | # ccc 24 | ] 25 | # ddd 26 | var y = [ 27 | # xxx 28 | 1, 29 | 2, 30 | 3, 31 | [ 32 | # yyy1 33 | 1, 34 | ], 35 | # yyy2 36 | 4, 37 | # zzz 38 | ] 39 | var z = { 40 | # qq3 41 | 1: 2, 42 | # ww3 43 | } 44 | 45 | 46 | func bar( 47 | # qq4 48 | a, 49 | # ww4 50 | b 51 | # ee4 52 | ): 53 | # rr4 54 | pass 55 | 56 | 57 | func baz(): 58 | bar( 59 | # qq5 60 | 1, 61 | # ww5 62 | 2 63 | # ee5 64 | ) 65 | -------------------------------------------------------------------------------- /gdtoolkit/formatter/exceptions.py: -------------------------------------------------------------------------------- 1 | from dataclasses import dataclass 2 | 3 | from ..common.exceptions import GDToolkitError 4 | 5 | 6 | @dataclass 7 | class TreeInvariantViolation(GDToolkitError): 8 | diff: str 9 | 10 | def __str__(self): 11 | return '{}(diff="{}")'.format("TreeInvariantViolation", self.diff) 12 | 13 | 14 | @dataclass 15 | class FormattingStabilityViolation(GDToolkitError): 16 | diff: str 17 | 18 | def __str__(self): 19 | return '{}(diff="{}")'.format("FormattingStabilityViolation", self.diff) 20 | 21 | 22 | @dataclass 23 | class CommentPersistenceViolation(GDToolkitError): 24 | missing_comment: str 25 | 26 | def __str__(self): 27 | return '{}(missing_comment="{}")'.format( 28 | "CommentPersistenceViolation", self.missing_comment 29 | ) 30 | -------------------------------------------------------------------------------- /gdtoolkit/linter/misc_checks.py: -------------------------------------------------------------------------------- 1 | from types import MappingProxyType 2 | from typing import List 3 | 4 | from lark import Tree 5 | 6 | from .problem import Problem 7 | from .if_return_checks import no_elif_return_check, no_else_return_check 8 | 9 | 10 | def lint(parse_tree: Tree, config: MappingProxyType) -> List[Problem]: 11 | disable = config["disable"] 12 | checks_to_run_w_tree = [ 13 | ( 14 | "no-elif-return", 15 | no_elif_return_check, 16 | ), 17 | ( 18 | "no-else-return", 19 | no_else_return_check, 20 | ), 21 | ] 22 | problem_clusters = ( 23 | x[1](parse_tree) if x[0] not in disable else [] for x in checks_to_run_w_tree 24 | ) 25 | problems = [problem for cluster in problem_clusters for problem in cluster] 26 | return problems 27 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/inline_properties.in.gd: -------------------------------------------------------------------------------- 1 | var p1: set = __set 2 | var p2: set = __set, get = __get 3 | var p3: get = __get 4 | var p4: get = __get, set = __set 5 | 6 | var p5 = 1: set = __set 7 | var p6 = 1: set = __set, get = __get 8 | var p7 = 1: get = __get 9 | var p8 = 1: get = __get, set = __set 10 | 11 | var p9 : int: set = __set 12 | var p10 : int: set = __set, get = __get 13 | var p11 : int: get = __get 14 | var p12 : int: get = __get, set = __set 15 | 16 | var p13 : int = 1: set = __set 17 | var p14 : int = 1: set = __set, get = __get 18 | var p15 : int = 1: get = __get 19 | var p16 : int = 1: get = __get, set = __set 20 | 21 | var p17 := 1: set = __set 22 | var p18 := 1: set = __set, get = __get 23 | var p19 := 1: get = __get 24 | var p20 := 1: get = __get, set = __set 25 | 26 | func __get(): 27 | return 1 28 | 29 | func __set(v): 30 | pass 31 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_boolean_test_expressions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var a = "xxxxxxxxxxxxxxxxxxxxxxxxxxx" > "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 4 | var b = [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] in [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 5 | var c = not not not not not not not not not not not not not not not not not not not not ! true 6 | var d = true && true && true && true && true && true and true and true and true and true and true 7 | var e = true || true or true or true or true or true or true or true or true or true or true or true or true or true or 1 > 1111 8 | var f = "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" if true else "yyyyyyyyyyyyyyyyyyyyyyyyyyyyy" 9 | var g = (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 10 | -------------------------------------------------------------------------------- /tests/formatter/common.py: -------------------------------------------------------------------------------- 1 | import difflib 2 | 3 | from gdtoolkit.formatter import format_code, check_formatting_safety 4 | 5 | 6 | MAX_LINE_LENGTH = 100 7 | 8 | 9 | def format_and_compare(input_code, expected_output_code, spaces_for_indent=None): 10 | formatted_code = format_code( 11 | input_code, 12 | max_line_length=MAX_LINE_LENGTH, 13 | spaces_for_indent=spaces_for_indent, 14 | ) 15 | _compare(formatted_code, expected_output_code) 16 | check_formatting_safety( 17 | input_code, formatted_code, MAX_LINE_LENGTH, spaces_for_indent=spaces_for_indent 18 | ) 19 | 20 | 21 | def _compare(formatted_code, expected_output_code): 22 | diff = "\n".join( 23 | difflib.unified_diff( 24 | expected_output_code.splitlines(), formatted_code.splitlines() 25 | ) 26 | ) 27 | assert formatted_code == expected_output_code, diff 28 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_signal_statements.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | signal a(x, y) 3 | signal b( 4 | aaaaaaaa, 5 | bbbbbbbbb, 6 | ccccccccc, 7 | dddddddd, 8 | eeeeeeee, 9 | ffffffff, 10 | ggggggggg, 11 | hhhhhhhh, 12 | iiiiiiii, 13 | jjjjjjjjjjj 14 | ) 15 | signal c( 16 | x, 17 | y, 18 | ) 19 | signal d( 20 | x: int, 21 | ) 22 | signal e(x, y: float) 23 | signal f( 24 | x: int, 25 | aaaaaaaa, 26 | bbbbbbbbb, 27 | ccccccccc, 28 | dddddddd, 29 | eeeeeeee, 30 | ffffffff, 31 | ggggggggg, 32 | hhhhhhhh, 33 | iiiiiiii, 34 | jjjjjjjjjjj, 35 | y: float 36 | ) 37 | signal g( 38 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx: int 39 | ) 40 | signal h( 41 | xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx 42 | ) 43 | -------------------------------------------------------------------------------- /gdtoolkit/formatter/constants.py: -------------------------------------------------------------------------------- 1 | from types import MappingProxyType 2 | 3 | 4 | TAB_INDENT_SIZE = 4 5 | INLINE_COMMENT_OFFSET = 2 6 | 7 | DEFAULT_SURROUNDING_EMPTY_LINES_TABLE = MappingProxyType( 8 | { 9 | "class_def": 1, 10 | "func_def": 1, 11 | "static_func_def": 1, 12 | "remote_func_def": 1, 13 | "remotesync_func_def": 1, 14 | "master_func_def": 1, 15 | "mastersync_func_def": 1, 16 | "puppet_func_def": 1, 17 | "sync_func_def": 1, 18 | } 19 | ) 20 | GLOBAL_SCOPE_SURROUNDING_EMPTY_LINES_TABLE = MappingProxyType( 21 | { 22 | "class_def": 2, 23 | "func_def": 2, 24 | "static_func_def": 2, 25 | "remote_func_def": 2, 26 | "remotesync_func_def": 2, 27 | "master_func_def": 2, 28 | "mastersync_func_def": 2, 29 | "puppet_func_def": 2, 30 | "sync_func_def": 2, 31 | } 32 | ) 33 | -------------------------------------------------------------------------------- /action.yml: -------------------------------------------------------------------------------- 1 | name: Godot toolkit install 2 | author: Pawel Lampe 3 | description: Install the Godot toolkit 4 | branding: 5 | icon: activity 6 | color: blue 7 | 8 | inputs: 9 | version: 10 | description: Version of the gdtoolkit to install 11 | default: "4.*" 12 | 13 | runs: 14 | using: composite 15 | steps: 16 | - id: create-requirements-if-not-exists 17 | run: | 18 | if [ ! -f requirements.txt ]; then 19 | echo "gdtoolkit==${{inputs.version}}" > requirements.txt 20 | fi 21 | shell: bash 22 | 23 | - id: install-python 24 | uses: actions/setup-python@v5 25 | with: 26 | python-version: "3.x" 27 | cache: "pip" 28 | 29 | - id: upgrade-setuptools 30 | run: pip install --upgrade setuptools 31 | shell: bash 32 | 33 | - id: install-gdtoolkit 34 | run: pip install gdtoolkit==${{inputs.version}} 35 | shell: bash 36 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_match_statements.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(x): 3 | match x: 4 | 1: 5 | pass 6 | 1, 2: 7 | pass 8 | "x": 9 | pass 10 | Vector2.ZERO.x: 11 | pass 12 | {"a":1,"b":2}: 13 | pass 14 | [1,..]: 15 | pass 16 | var a: 17 | pass 18 | (1): 19 | pass 20 | ~1: 21 | pass 22 | -1: 23 | pass 24 | +1: 25 | pass 26 | 1*1: 27 | pass 28 | 1+1: 29 | pass 30 | 1<<1: 31 | pass 32 | 1&1: 33 | pass 34 | 1^1: 35 | pass 36 | 1|1: 37 | pass 38 | 1>1: 39 | pass 40 | not 1: 41 | pass 42 | 1 and 2: 43 | pass 44 | 1 or 2: 45 | pass 46 | 1 if 1 else 2: 47 | pass 48 | 2 when true: 49 | pass 50 | 2 when 1 == 1: 51 | pass 52 | 2 when 1.0 as int: 53 | pass 54 | _: 55 | pass 56 | match Vector3(1,1,1): 57 | Vector3(1,1+1,1): 58 | pass 59 | -------------------------------------------------------------------------------- /tests/gdradon/test_executable.py: -------------------------------------------------------------------------------- 1 | import subprocess 2 | 3 | from ..common import write_file 4 | 5 | 6 | def test_cc_on_empty_file_succeeds(tmp_path): 7 | dummy_file = write_file(tmp_path, "script.gd", "") 8 | outcome = subprocess.run( 9 | ["gdradon", "cc", dummy_file], check=False, capture_output=True 10 | ) 11 | assert outcome.returncode == 0 12 | assert len(outcome.stdout.decode().splitlines()) == 0 13 | assert len(outcome.stderr.decode().splitlines()) == 0 14 | 15 | 16 | def test_cc_on_file_with_single_function_succeeds(tmp_path): 17 | dummy_file = write_file(tmp_path, "script.gd", "func foo(): pass\n") 18 | outcome = subprocess.run( 19 | ["gdradon", "cc", dummy_file], check=False, capture_output=True 20 | ) 21 | assert outcome.returncode == 0 22 | assert len(outcome.stdout.decode().splitlines()) == 2 23 | assert len(outcome.stderr.decode().splitlines()) == 0 24 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/type_cast_corner_case_expressions.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | 1 as int or [1,2] ==[1,2] 3 | 1 as int or [1,2,] ==[1,2,] 4 | # --- 5 | 1 as int if true else 2 if true else 3 6 | 1 as int if true else 2 if [1,] else 3 7 | # --- 8 | 1 as int or true and true 9 | 1 as int or [1,] and true 10 | # --- 11 | not 1 in [0] 12 | not 1 in [0,] 13 | # --- 14 | 1 as int if true or true else true 15 | 1 as int if [1,] or true else true 16 | # --- 17 | 1 as int or 1|1 18 | 1 as int or [1,]|1 19 | # --- 20 | 1 as int or 1^1 21 | 1 as int or [1,]^1 22 | # --- 23 | 1 as int or 1&1 24 | 1 as int or [1,]&1 25 | # --- 26 | 1 as int or 1<<1 27 | 1 as int or [1,]<<1 28 | # --- 29 | 1 as int or 1*1 30 | 1 as int or [1,]*1 31 | # --- 32 | 1 as int or 1+1 33 | 1 as int or [1,]-1 34 | # --- 35 | 1 as int or 1 is int1 36 | 1 as int or [1,] is Array 37 | # -- 38 | 1 as int or 1**1 39 | 1 as int or [1,]**2 40 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/subscription_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(p): 3 | var x = p[0][[1, 2, 3]] 4 | var y = p[[1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]][[ 5 | 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1 6 | ]] 7 | var z = { 8 | x.yyyyyyyy.zzzzz.a: "locked", 9 | x.yyyyyyyy.zzzzz.b: "unlocked", 10 | x.yyyyyyyy.zzzzz.c: "done", 11 | }[x] 12 | var a = p[ 13 | 1 14 | + 1 15 | + 1 16 | + 1 17 | + 1 18 | + 1 19 | + 1 20 | + 1 21 | + 1 22 | + 1 23 | + 1 24 | + 1 25 | + 1 26 | + 1 27 | + 1 28 | + 1 29 | + 1 30 | + 1 31 | + 1 32 | + 1 33 | + 1 34 | + 1 35 | + 1 36 | + 1 37 | + 1 38 | + 1 39 | + 1 40 | + 1 41 | + 1 42 | + 1 43 | + 1 44 | + 1 45 | + 1 46 | + 1 47 | + 1 48 | + 1 49 | + 1 50 | + 1 51 | + 1 52 | + 1 53 | + 1 54 | ] 55 | var b = p[[ 56 | 1, 57 | 2, 58 | 3, 59 | ]] 60 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_match_statements.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(x): 3 | match x: 4 | 1: 5 | pass 6 | 1, 2: 7 | pass 8 | "x": 9 | pass 10 | Vector2.ZERO.x: 11 | pass 12 | {"a": 1, "b": 2}: 13 | pass 14 | [1, ..]: 15 | pass 16 | var a: 17 | pass 18 | (1): 19 | pass 20 | ~1: 21 | pass 22 | -1: 23 | pass 24 | +1: 25 | pass 26 | 1 * 1: 27 | pass 28 | 1 + 1: 29 | pass 30 | 1 << 1: 31 | pass 32 | 1 & 1: 33 | pass 34 | 1 ^ 1: 35 | pass 36 | 1 | 1: 37 | pass 38 | 1 > 1: 39 | pass 40 | not 1: 41 | pass 42 | 1 and 2: 43 | pass 44 | 1 or 2: 45 | pass 46 | 1 if 1 else 2: 47 | pass 48 | 2 when true: 49 | pass 50 | 2 when 1 == 1: 51 | pass 52 | 2 when 1.0 as int: 53 | pass 54 | _: 55 | pass 56 | match Vector3(1, 1, 1): 57 | Vector3(1, 1 + 1, 1): 58 | pass 59 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/annotations.gd: -------------------------------------------------------------------------------- 1 | @tool 2 | extends Node 3 | 4 | var x 5 | 6 | @onready 7 | 8 | @export_range(1, 100, 1, "or_greater") 9 | var ranged_var: int = 50 10 | 11 | @onready @export_range(1, 100, 1, "or_greater") var ranged_var_2: int = 50 12 | 13 | # @onready func foo(): 14 | # pass 15 | # @onready 16 | # func bar(): 17 | # pass 18 | # @onready const X = 1 19 | # @master var x 20 | 21 | @onready @export_range(1, 100, 1, "or_greater") 22 | var ranged_var_3: int = 50 23 | 24 | pass;pass 25 | @onready var y;pass 26 | @onready @export_range(1, 100, 1, "or_greater") var ranged_var_4: int = 50;pass 27 | @onready @export_range(1, 100, 1, "or_greater") var ranged_var_5: int = 50;@onready @export_range(1, 100, 1, "or_greater") var ranged_var_6: int = 50 28 | 29 | # invalid: 30 | # @onready() var z;pass 31 | # @onready() 32 | # var q; 33 | @onready @export_range(1, 100, 1, "or_greater",) var ranged_var_7: int = 50 34 | 35 | class Foo: 36 | extends Node 37 | @onready var asd 38 | -------------------------------------------------------------------------------- /tests/potential-godot-bugs/lambda_corner_case.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func foo(): 4 | pass 5 | 6 | func _ready() -> void: 7 | get_tree().create_timer(1.0).timeout.connect(foo) # works 8 | get_tree().create_timer(1.0).timeout.connect(func(): foo()) # works 9 | get_tree().create_timer(1.0).timeout.connect( 10 | func(): 11 | foo() 12 | ) # works 13 | ( 14 | get_tree() 15 | . create_timer(1.0) 16 | . timeout 17 | . connect(foo) 18 | ) # works 19 | ( 20 | get_tree() 21 | . create_timer(1.0) 22 | . timeout 23 | . connect(func(): foo()) 24 | ) # works 25 | ( 26 | get_tree() 27 | . create_timer(1.0) 28 | . timeout 29 | . connect( 30 | func(): foo() 31 | ) 32 | ) # works 33 | ( 34 | get_tree() 35 | . create_timer(1.0) 36 | . timeout 37 | . connect( 38 | func(): 39 | foo()) 40 | ) # works ! 41 | ( 42 | get_tree() 43 | . create_timer(1.0) 44 | . timeout 45 | . connect( 46 | func(): 47 | foo() 48 | ) 49 | ) # doesn't work ! 50 | -------------------------------------------------------------------------------- /tests/formatter/test_real_world_scripts.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from gdtoolkit.formatter import format_code, check_formatting_safety 4 | 5 | 6 | DATA_DIR = "./big-input-files" 7 | MAX_LINE_LENGTH = 100 8 | 9 | 10 | def pytest_generate_tests(metafunc): 11 | this_directory = os.path.dirname(os.path.abspath(__file__)) 12 | if "test_name" in metafunc.fixturenames: 13 | tests_in_dir = os.path.join(this_directory, DATA_DIR) 14 | metafunc.parametrize( 15 | "test_name", 16 | os.listdir(tests_in_dir), 17 | ) 18 | 19 | 20 | def test_real_world_script(test_name): 21 | this_dir = os.path.dirname(os.path.abspath(__file__)) 22 | input_file_path = os.path.join(this_dir, DATA_DIR, test_name) 23 | with open(input_file_path, "r", encoding="utf-8") as input_handle: 24 | input_code = input_handle.read() 25 | formatted_code = format_code(input_code, MAX_LINE_LENGTH) 26 | check_formatting_safety(input_code, formatted_code, MAX_LINE_LENGTH) 27 | -------------------------------------------------------------------------------- /tests/linter/common.py: -------------------------------------------------------------------------------- 1 | from gdtoolkit.linter import lint_code, DEFAULT_CONFIG 2 | from gdtoolkit.common.utils import get_line 3 | 4 | 5 | def simple_ok_check(code, **kwargs): 6 | extra_disable = [] if "disable" not in kwargs else kwargs["disable"] 7 | config = DEFAULT_CONFIG.copy() 8 | config.update({"disable": extra_disable}) 9 | outcome = lint_code(code, config) 10 | assert len(outcome) == 0, outcome 11 | 12 | 13 | def simple_nok_check(code, check_name, line=2, **kwargs): 14 | extra_disable = [] if "disable" not in kwargs else kwargs["disable"] 15 | config_w_disable = DEFAULT_CONFIG.copy() 16 | config_w_disable.update({"disable": [check_name] + extra_disable}) 17 | assert len(lint_code(code, config_w_disable)) == 0 18 | 19 | config = DEFAULT_CONFIG.copy() 20 | config.update({"disable": extra_disable}) 21 | outcome = lint_code(code, config) 22 | assert len(outcome) == 1 23 | assert outcome[0].name == check_name 24 | assert get_line(outcome[0]) == line 25 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_dict_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var x = { 4 | "a": 1, "b": 1, "c": 1, "d": 1, "e": 1, "f": 1, "g": 1, "h": 1, "i": 1, "j": 1, "k": 1 5 | } 6 | var y = { 7 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]: 8 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 9 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1]: 10 | [ 11 | 1, 12 | 1, 13 | 1, 14 | 1, 15 | 1, 16 | 1, 17 | 1, 18 | 1, 19 | 1, 20 | 1, 21 | 1, 22 | 1, 23 | 1, 24 | 1, 25 | 1, 26 | 1, 27 | 1, 28 | 1, 29 | 1, 30 | 1, 31 | 1, 32 | 1, 33 | 1, 34 | 1, 35 | 1, 36 | 1, 37 | 1, 38 | 1, 39 | 1, 40 | 1, 41 | 1 42 | ], 43 | } 44 | var z = { 45 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx": 46 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1], 47 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxy": 48 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 49 | } 50 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_properties_w_comments.in.gd: -------------------------------------------------------------------------------- 1 | # a 2 | var p1: # inline a 3 | # b 4 | set = __set # inline b 5 | # c 6 | # d 7 | var p2: # inline c 8 | # e 9 | set = __set, # inline d 10 | # f 11 | get = __get # inline e 12 | # g 13 | var p3: 14 | get = __get 15 | var p4: 16 | get = __get, 17 | set = __set 18 | 19 | var p5: 20 | get: pass 21 | var p6: 22 | get: 23 | pass 24 | var p7: 25 | set(_x): pass 26 | var p8: 27 | set(_x): 28 | pass 29 | 30 | # h 31 | var p9: # inline f 32 | # i 33 | set(_x): pass # inline g 34 | # j 35 | get: return 1 # inline h 36 | # k 37 | # l 38 | var p10: # inline i 39 | # m 40 | get: # inline j 41 | # n 42 | var xyz = 123 # inline k 43 | # o 44 | return xyz # inline l 45 | # p 46 | set(x): # inline m 47 | # q 48 | var xyz = 234 # inline n 49 | # r 50 | p8 = x + 1 + xyz # inline o 51 | # s 52 | # t 53 | # u 54 | 55 | func __get(): 56 | return 1 57 | 58 | func __set(v): 59 | pass 60 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/multiline_properties_w_comments.out.gd: -------------------------------------------------------------------------------- 1 | # a 2 | var p1: # inline a 3 | # b 4 | set = __set # inline b 5 | # c 6 | # d 7 | var p2: # inline c 8 | # e 9 | set = __set, # inline d 10 | # f 11 | get = __get # inline e 12 | # g 13 | var p3: 14 | get = __get 15 | var p4: 16 | get = __get, 17 | set = __set 18 | 19 | var p5: 20 | get: 21 | pass 22 | var p6: 23 | get: 24 | pass 25 | var p7: 26 | set(_x): 27 | pass 28 | var p8: 29 | set(_x): 30 | pass 31 | 32 | # h 33 | var p9: # inline f 34 | # i 35 | set(_x): 36 | pass # inline g 37 | # j 38 | get: 39 | return 1 # inline h 40 | # k 41 | # l 42 | var p10: # inline i 43 | # m 44 | get: # inline j 45 | # n 46 | var xyz = 123 # inline k 47 | # o 48 | return xyz # inline l 49 | # p 50 | set(x): # inline m 51 | # q 52 | var xyz = 234 # inline n 53 | # r 54 | p8 = x + 1 + xyz # inline o 55 | # s 56 | # t 57 | # u 58 | 59 | 60 | func __get(): 61 | return 1 62 | 63 | 64 | func __set(v): 65 | pass 66 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/inline_properties.out.gd: -------------------------------------------------------------------------------- 1 | var p1: 2 | set = __set 3 | var p2: 4 | set = __set, 5 | get = __get 6 | var p3: 7 | get = __get 8 | var p4: 9 | get = __get, 10 | set = __set 11 | 12 | var p5 = 1: 13 | set = __set 14 | var p6 = 1: 15 | set = __set, 16 | get = __get 17 | var p7 = 1: 18 | get = __get 19 | var p8 = 1: 20 | get = __get, 21 | set = __set 22 | 23 | var p9: int: 24 | set = __set 25 | var p10: int: 26 | set = __set, 27 | get = __get 28 | var p11: int: 29 | get = __get 30 | var p12: int: 31 | get = __get, 32 | set = __set 33 | 34 | var p13: int = 1: 35 | set = __set 36 | var p14: int = 1: 37 | set = __set, 38 | get = __get 39 | var p15: int = 1: 40 | get = __get 41 | var p16: int = 1: 42 | get = __get, 43 | set = __set 44 | 45 | var p17 := 1: 46 | set = __set 47 | var p18 := 1: 48 | set = __set, 49 | get = __get 50 | var p19 := 1: 51 | get = __get 52 | var p20 := 1: 53 | get = __get, 54 | set = __set 55 | 56 | 57 | func __get(): 58 | return 1 59 | 60 | 61 | func __set(v): 62 | pass 63 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/inline_properties_w_comments.in.gd: -------------------------------------------------------------------------------- 1 | # a 2 | var p1: set = __set # inline a 3 | # b 4 | var p2: set = __set, get = __get # inline b 5 | # c 6 | var p3: get = __get # inline c 7 | # d 8 | var p4: get = __get, set = __set # inline d 9 | # e 10 | 11 | # f 12 | var p5 = 1: set = __set # inline e 13 | # g 14 | var p6 = 1: set = __set, get = __get # inline f 15 | # h 16 | var p7 = 1: get = __get # inline g 17 | # i 18 | var p8 = 1: get = __get, set = __set # inline h 19 | # j 20 | 21 | var p9 : int: set = __set 22 | var p10 : int: set = __set, get = __get 23 | var p11 : int: get = __get 24 | var p12 : int: get = __get, set = __set 25 | 26 | var p13 : int = 1: set = __set 27 | var p14 : int = 1: set = __set, get = __get 28 | var p15 : int = 1: get = __get 29 | var p16 : int = 1: get = __get, set = __set 30 | 31 | var p17 := 1: set = __set 32 | var p18 := 1: set = __set, get = __get 33 | var p19 := 1: get = __get 34 | var p20 := 1: get = __get, set = __set 35 | 36 | func __get(): 37 | return 1 38 | 39 | func __set(v): 40 | pass 41 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/literals.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func foo(): 4 | 123 5 | "asdf" 6 | 3.1415926 7 | 58.1e-10 8 | 'asdf' 9 | """single line""" 10 | """x"x""" 11 | ^"asdf/dfg" 12 | &"xxx" 13 | $Node 14 | $"../xxx" 15 | 0xaf01 16 | 0xAfA01 17 | 0b0101111 18 | 012 19 | null 20 | 21 | func assert_string_contains(text, search, match_case=true): 22 | var empty_search = "Expected text and search strings to be non-empty. You passed \"%s\" and \"%s\"." 23 | var disp = "Expected \"%s\" to contain \"%s\", match_case=%s" % [text, search, match_case] 24 | 25 | func assert_string_contains2(text, search, match_case=true): 26 | var empty_search = 'Expected text and search strings to be non-empty. You passed \'%s\' and \'%s\'.' 27 | var disp = 'Expected \'%s\' to contain \'%s\', match_case=%s' % [text, search, match_case] 28 | 29 | 30 | const GREETING = """Hello Merchant! 31 | Welcome to the first tutorial. 32 | My name is Siegfried and I'll assist you throughout the game. 33 | In this tutorial, I'll walk you through the basic game mechanics. 34 | Go ahead and click "Next" to start.""" 35 | -------------------------------------------------------------------------------- /gdtoolkit/gd2py/__main__.py: -------------------------------------------------------------------------------- 1 | """GDScript-to-python converter 2 | 3 | Experimental converter which produces syntactically correct python3 out of given 4 | GDScript. Produced python code almost for sure will not be runnable, although its 5 | core structure should be the same as of GDScript thus allowing usage of various 6 | python static analysis tools like e.g. radon. 7 | 8 | Usage: 9 | gd2py [options] 10 | 11 | Options: 12 | -h --help Show this screen. 13 | --version Show version. 14 | 15 | Examples: 16 | gd2py file.gd # produces python file on stdout 17 | gd2py ./addons/gut/gut.gd | radon cc -s - 18 | """ 19 | import sys 20 | from importlib.metadata import version as pkg_version 21 | 22 | from docopt import docopt 23 | 24 | from . import convert_code 25 | 26 | 27 | def main(): 28 | sys.stdout.reconfigure(encoding="utf-8") 29 | arguments = docopt( 30 | __doc__, 31 | version="gd2py {}".format(pkg_version("gdtoolkit")), 32 | ) 33 | with open(arguments[""], "r", encoding="utf-8") as handle: 34 | print(convert_code(handle.read())) 35 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/expressions.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | enum Xyz { AAA } 4 | 5 | const XXXX = preload('functions.gd') 6 | 7 | class Zyx: 8 | enum Qwe { BBB } 9 | 10 | class XNode extends Node: 11 | class YNode extends Node: 12 | pass 13 | 14 | func bar(): 15 | pass 16 | 17 | func foo(): 18 | var x 19 | 1 if true else 2 20 | 1 or 2 21 | 1 || 2 22 | 1 and 3 23 | 1 && 3 24 | not 5 25 | ! 5 26 | 5 in x 27 | 1 > 2 28 | 1 < 2 29 | 1 == 2 30 | 1 != 1 31 | 1 >= 12 32 | 2 <= 43 33 | 3 | 3 34 | 6 ^ 5 35 | 8 & 7 36 | 5 >> 7 37 | 7 << 5 38 | 5 - 6 39 | 6 + 7 40 | 7 * 7 41 | 7 / 8 42 | 6 % 3 43 | -8 44 | ~8 45 | 5 ** 5 46 | x is int 47 | x is not int 48 | x is Xyz # TODO: fix/remove x.Type 49 | x is Zyx.Qwe # TODO: fix/remove x.Type 50 | x.attr 51 | x[10] 52 | bar() 53 | (2+2) 54 | var xxxx = XXXX.new() 55 | xxxx.fun(1, 2) 56 | x[1][2][3]['xxx'][1+2] 57 | x[1] += 2 58 | x[1] ^= 2 59 | x[1] >>= 2 60 | x[1] <<= 2 61 | x[1] **= 2 62 | x.bar()[1] 63 | x.attr = 34 64 | 1_000_000 > 0 65 | 1_000.000 > 0.0 66 | 0xff_99_00 > 0 67 | x as XNode.YNode 68 | x as XNode . YNode 69 | 70 | class Foo: 71 | pass 72 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | MIT License 2 | 3 | Copyright (c) 2019 Pawel Lampe 4 | 5 | Permission is hereby granted, free of charge, to any person obtaining a copy 6 | of this software and associated documentation files (the "Software"), to deal 7 | in the Software without restriction, including without limitation the rights 8 | to use, copy, modify, merge, publish, distribute, sublicense, and/or sell 9 | copies of the Software, and to permit persons to whom the Software is 10 | furnished to do so, subject to the following conditions: 11 | 12 | The above copyright notice and this permission notice shall be included in all 13 | copies or substantial portions of the Software. 14 | 15 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 16 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 17 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 18 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 19 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 20 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 21 | SOFTWARE. 22 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/negation_n_bitwise_not_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var e 4 | var x = ~e 5 | var y = ~( 6 | 1 7 | + 1 8 | + 1 9 | + 1 10 | + 1 11 | + 1 12 | + 1 13 | + 1 14 | + 1 15 | + 1 16 | + 1 17 | + 1 18 | + 1 19 | + 1 20 | + 1 21 | + 1 22 | + 1 23 | + 1 24 | + 1 25 | + 1 26 | + 1 27 | + 1 28 | + 1 29 | + 1 30 | + 1 31 | + 1 32 | + 1 33 | + 1 34 | + 1 35 | + 1 36 | + 1 37 | + 1 38 | + 1 39 | + 1 40 | + 1 41 | + 1 42 | + 1 43 | + 1 44 | + 1 45 | + 1 46 | + 1 47 | ) 48 | var q = -x 49 | var w = -( 50 | 1 51 | + 1 52 | + 1 53 | + 1 54 | + 1 55 | + 1 56 | + 1 57 | + 1 58 | + 1 59 | + 1 60 | + 1 61 | + 1 62 | + 1 63 | + 1 64 | + 1 65 | + 1 66 | + 1 67 | + 1 68 | + 1 69 | + 1 70 | + 1 71 | + 1 72 | + 1 73 | + 1 74 | + 1 75 | + 1 76 | + 1 77 | + 1 78 | + 1 79 | + 1 80 | + 1 81 | + 1 82 | + 1 83 | + 1 84 | + 1 85 | + 1 86 | + 1 87 | + 1 88 | + 1 89 | + 1 90 | + 1 91 | ) 92 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/inline_lambdas_w_comments.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | # a 3 | var x1 = func(): pass # inline a 4 | # b 5 | 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): pass # inline b 6 | # c 7 | var x3 = func baz( # inline c 8 | # d 9 | p1, # inline d 10 | # e 11 | p2, 12 | p3, 13 | p4, 14 | p5, 15 | p6, 16 | p7, 17 | p8, 18 | p9, 19 | p10, 20 | p11, 21 | p12, 22 | p13, 23 | p14, 24 | p15, 25 | p16, 26 | p17, 27 | p18, 28 | p19, 29 | p20, 30 | p21, 31 | p22, 32 | p23 # inline e 33 | # f 34 | ) -> int: pass ; pass ; var x := [ # inline f 35 | # g 36 | 0, # inline g 37 | # h 38 | 0, 39 | 0, 40 | 0, 41 | 0, 42 | 0, 43 | 0, 44 | 0, 45 | 0, 46 | 0, 47 | 0, 48 | 0, 49 | 0, 50 | 0, 51 | 0, 52 | 0, 53 | 0, 54 | 0, 55 | 0, 56 | 0, 57 | 0, 58 | 0, 59 | 0, 60 | 0, 61 | 0, 62 | 0, 63 | 0, 64 | 0, 65 | 0, 66 | 0, 67 | 0, 68 | 0, 69 | 0, 70 | 0, 71 | 0, 72 | 0, 73 | 0, 74 | 0, 75 | 0 # inline h 76 | # i 77 | ] ; pass # inline i 78 | # j 79 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/edge_func_calls.gd: -------------------------------------------------------------------------------- 1 | func oa(a): 2 | pass 3 | 4 | func x(): 5 | oa(1) 6 | 7 | func xx(): 8 | oa(1 9 | ) 10 | 11 | func xxx(): 12 | oa( 13 | 1 14 | ) 15 | 16 | func xxxx(): 17 | oa( 18 | 1) 19 | 20 | func ta(a,b,c): 21 | pass 22 | 23 | func y(): 24 | ta(1,2,3 25 | ) 26 | 27 | func yy(): 28 | ta( 29 | 1, 30 | 2, 31 | 3) 32 | 33 | func yyy(): 34 | ta( 35 | 1, 36 | 2, 37 | 3 38 | ) 39 | 40 | func yyyy(): 41 | ta( 42 | 1,2,3) 43 | 44 | func yyyyy(): 45 | ta( 46 | 1,2,3 47 | ) 48 | 49 | func z(): 50 | ta( 51 | 1, 2, 3) 52 | pass 53 | 54 | func zz(): 55 | ta(1,2,3) 56 | pass 57 | 58 | var _viewport 59 | func _update_camera_rect(x): 60 | pass 61 | func foo(): 62 | _update_camera_rect(_update_camera_rect(1)) 63 | func _on_camera_update(camera): 64 | _update_camera_rect(Rect2( 65 | camera.get_camera_position() + camera.offset \ 66 | - Vector2(_viewport.size.x/2.0, _viewport.size.y/2.0), _viewport.size)) 67 | func _on_camera_update2(camera): 68 | _update_camera_rect(Rect2( 69 | camera.get_camera_position() + camera.offset \ 70 | - Vector2(_viewport.size.x/2.0, _viewport.size.y/2.0), _viewport.size) 71 | ) 72 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_attribute_expression_corner_case.out.gd: -------------------------------------------------------------------------------- 1 | func foo(x): 2 | var path: String = ( 3 | x 4 | . result 5 | . path 6 | . substr(0, 10) 7 | . replace("res://", "") 8 | . replace("tests/", "") 9 | . replace("", "") 10 | . replace("", "") 11 | . replace("", "") 12 | . replace("", "") 13 | . replace("", "") 14 | . replace("/", " ") 15 | . capitalize( 16 | 1, 17 | 2, 18 | 3, 19 | 4, 20 | 6, 21 | 7, 22 | 8, 23 | 9, 24 | 10, 25 | 11, 26 | 12, 27 | 13, 28 | 14, 29 | 15, 30 | 16, 31 | 17, 32 | 18, 33 | 19, 34 | 20, 35 | 21, 36 | 22, 37 | 23, 38 | 24, 39 | 25, 40 | 26, 41 | 27, 42 | 28 43 | ) 44 | ) 45 | var path2 = ( 46 | x 47 | . aaaa 48 | . bbbb 49 | . ccccc() 50 | . ddddd 51 | . eeee 52 | . ffff( 53 | 1, 54 | 2, 55 | 3, 56 | 4, 57 | 6, 58 | 7, 59 | 8, 60 | 9, 61 | 10, 62 | 11, 63 | 12, 64 | 13, 65 | 14, 66 | 15, 67 | 16, 68 | 17, 69 | 18, 70 | 19, 71 | 20, 72 | 21, 73 | 22, 74 | 23, 75 | 24, 76 | 25, 77 | 26, 78 | 27, 79 | 28 80 | ) 81 | . gggg() 82 | . hhhh 83 | . jjjj 84 | ) 85 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_function_definitions.in.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(a=["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"]): 3 | pass 4 | 5 | func bar(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb): 6 | pass 7 | 8 | func baz(a=["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"], b=[]): 9 | pass 10 | 11 | func bax (a,b:=["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"]): 12 | pass 13 | 14 | func bac(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb:int): 15 | pass 16 | 17 | func bav(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa,bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb:Array = ["aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa","bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb"]): 18 | pass 19 | 20 | func bab(aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbb, ccccccccccccccccccccc, ddddddddddddddd,): 21 | pass 22 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/inline_properties_w_comments.out.gd: -------------------------------------------------------------------------------- 1 | # a 2 | var p1: 3 | set = __set # inline a 4 | # b 5 | var p2: 6 | set = __set, 7 | get = __get # inline b 8 | # c 9 | var p3: 10 | get = __get # inline c 11 | # d 12 | var p4: 13 | get = __get, 14 | set = __set # inline d 15 | # e 16 | 17 | # f 18 | var p5 = 1: 19 | set = __set # inline e 20 | # g 21 | var p6 = 1: 22 | set = __set, 23 | get = __get # inline f 24 | # h 25 | var p7 = 1: 26 | get = __get # inline g 27 | # i 28 | var p8 = 1: 29 | get = __get, 30 | set = __set # inline h 31 | # j 32 | 33 | var p9: int: 34 | set = __set 35 | var p10: int: 36 | set = __set, 37 | get = __get 38 | var p11: int: 39 | get = __get 40 | var p12: int: 41 | get = __get, 42 | set = __set 43 | 44 | var p13: int = 1: 45 | set = __set 46 | var p14: int = 1: 47 | set = __set, 48 | get = __get 49 | var p15: int = 1: 50 | get = __get 51 | var p16: int = 1: 52 | get = __get, 53 | set = __set 54 | 55 | var p17 := 1: 56 | set = __set 57 | var p18 := 1: 58 | set = __set, 59 | get = __get 60 | var p19 := 1: 61 | get = __get 62 | var p20 := 1: 63 | get = __get, 64 | set = __set 65 | 66 | 67 | func __get(): 68 | return 1 69 | 70 | 71 | func __set(v): 72 | pass 73 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_dot_chains.in.gd: -------------------------------------------------------------------------------- 1 | func cccc(a,b,c): 2 | pass 3 | func foo(aaaaa): 4 | var x = aaaaa.bbbbb.cccc[1].ddd().ffff.ggg.hhh().iii.jjj.kkkkkkk.llllllll.mmmmmmm.nnnnnnnn.ooooo.ppppppppppp 5 | var y = aaaaa.bbbbb.cccc[[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,1,1,1,1,1,1,1,1]].ddd().ffff.ggg.hhh().iii.jjj.kkkkkkk.llllllll.mmmmmmm.nnnnnnnn.ooooo.ppppppppppp 6 | var z = aaaaa.bbbbb.cccc[0][1].ddd().ffff.ggg.hhh().iii.jjj.kkkkkkk.llllllll.mmmmmmm.nnnnnnnn.ooooo.ppppppppppp 7 | var q = aaaaa.bbbbb.cccc(1,2,3)[1].ddd().ffff.ggg.hhh().iii.jjj.kkkkkkk.llllllll.mmmmmmm.nnnnnnnn.ooooo.ppppppppppp 8 | var w = cccc(1,2,3)[1].ddd().ffff.ggg.hhh().iii.jjj.kkkkkkk.llllllll.mmmmmmm.nnnnnnnn.ooooo.ppppppppppp.aaaaa.bbbbb 9 | var e = cccc(1,2,3)[1].ddd().ffff.ggg.hhh().iii.jjj.kkkkkkk.llllllll.mmmmmmm.nnnnnnnn.ooooo.ppppppppppp.aaaaa.bbbbb[1] 10 | var r = {1:aaaaa}[1].ddd().ffff.ggg.hhh().iii.jjj.kkkkkkk.llllllll.mmmmmmm.nnnnnnnn.ooooo.ppppppppppp.aaaaa.bbbbb[1] 11 | var t = aaaaa.bbbbb.cccc[1].ddd().ffff.ggg.hhh().iii.jjj.kkkkkkk.llllllll.mmmmmmm.nnnnnnnn(1,2,3,4,5,6,7,8,9) 12 | var u = aaaaa.bbbbb.cccc[1].ddd().ffff.ggg.hhh().iii.jjj.kkkkkkk.llllllll.mmmmmmm.nnnnnnnn[(1+2+3+4+5+6+7+8+9)] 13 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/power_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var a 4 | var b = 1 ** 2 5 | var c = ( 6 | 1 7 | ** ( 8 | 1 9 | + 1 10 | + 1 11 | + 1 12 | + 1 13 | + 1 14 | + 1 15 | + 1 16 | + 1 17 | + 1 18 | + 1 19 | + 1 20 | + 1 21 | + 1 22 | + 1 23 | + 1 24 | + 1 25 | + 1 26 | + 1 27 | + 1 28 | + 1 29 | + 1 30 | + 1 31 | + 1 32 | + 1 33 | + 1 34 | + 1 35 | + 1 36 | + 1 37 | + 1 38 | + 1 39 | + 1 40 | + 1 41 | + 1 42 | + 1 43 | + 1 44 | + 1 45 | + 1 46 | + 1 47 | + 1 48 | + 1 49 | ) 50 | ) 51 | var d = ( 52 | ( 53 | 1 54 | + 1 55 | + 1 56 | + 1 57 | + 1 58 | + 1 59 | + 1 60 | + 1 61 | + 1 62 | + 1 63 | + 1 64 | + 1 65 | + 1 66 | + 1 67 | + 1 68 | + 1 69 | + 1 70 | + 1 71 | + 1 72 | + 1 73 | + 1 74 | + 1 75 | + 1 76 | + 1 77 | + 1 78 | + 1 79 | + 1 80 | + 1 81 | + 1 82 | + 1 83 | + 1 84 | + 1 85 | + 1 86 | + 1 87 | + 1 88 | + 1 89 | + 1 90 | + 1 91 | + 1 92 | + 1 93 | + 1 94 | ) 95 | ** 2 96 | ) 97 | -------------------------------------------------------------------------------- /.github/workflows/deploy.yml: -------------------------------------------------------------------------------- 1 | name: Deploy Python package to PyPI 2 | 3 | on: 4 | release: 5 | types: [created] 6 | 7 | jobs: 8 | build-n-publish: 9 | runs-on: ubuntu-latest 10 | 11 | steps: 12 | - name: Checkout repository 13 | uses: actions/checkout@v4 14 | 15 | - name: Set up Python 16 | uses: actions/setup-python@v5 17 | with: 18 | python-version: '3.8' 19 | 20 | - name: Install pypa/build 21 | run: >- 22 | python -m 23 | pip install 24 | build 25 | --user 26 | - name: Build a binary wheel and a source tarball 27 | run: >- 28 | python -m 29 | build 30 | --sdist 31 | --wheel 32 | --outdir dist/ 33 | . 34 | - name: Publish distribution package to Test PyPI 35 | uses: pypa/gh-action-pypi-publish@master 36 | with: 37 | password: ${{ secrets.TEST_PYPI_API_TOKEN }} 38 | repository_url: https://test.pypi.org/legacy/ 39 | 40 | - name: Publish distribution package to PyPI 41 | if: startsWith(github.ref, 'refs/tags') 42 | uses: pypa/gh-action-pypi-publish@master 43 | with: 44 | password: ${{ secrets.PYPI_API_TOKEN }} 45 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/call_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class Y: 2 | func f( 3 | a0, 4 | a1, 5 | a2, 6 | a3, 7 | a4, 8 | a5, 9 | a6, 10 | a7, 11 | a8, 12 | a9, 13 | a10, 14 | a11, 15 | a12, 16 | a13, 17 | a14, 18 | a15, 19 | a16, 20 | a17, 21 | a18, 22 | a19, 23 | a20, 24 | a21, 25 | a22, 26 | a23, 27 | a24, 28 | a25, 29 | a26, 30 | a27, 31 | a28 32 | ): 33 | pass 34 | 35 | func g(): 36 | pass 37 | 38 | 39 | class X: 40 | extends Y 41 | 42 | func bar(): 43 | pass 44 | 45 | func foo(a): 46 | var x = bar() 47 | var z = a.b.c(1, 2) 48 | var zz = ( 49 | a 50 | . b 51 | . c( 52 | 1, 53 | 2, 54 | ) 55 | ) 56 | var q = f( 57 | 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 58 | ) 59 | var qq = f( 60 | 1, 61 | 1, 62 | 1, 63 | 1, 64 | 1, 65 | 1, 66 | 1, 67 | 1, 68 | 1, 69 | 1, 70 | 1, 71 | 1, 72 | 1, 73 | 1, 74 | 1, 75 | 1, 76 | 1, 77 | 1, 78 | 1, 79 | 1, 80 | 1, 81 | 1, 82 | 1, 83 | 1, 84 | 1, 85 | 1, 86 | 1, 87 | 1, 88 | 1, 89 | ) 90 | var e = a.f( 91 | 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 92 | ) 93 | -------------------------------------------------------------------------------- /tests/linter/test_class_checks.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from .common import simple_ok_check, simple_nok_check 4 | 5 | 6 | # fmt: off 7 | @pytest.mark.parametrize('code', [ 8 | """ 9 | pass 10 | class_name Foo 11 | extends Node 12 | "docstring" 13 | signal s 14 | enum { A, B, C } 15 | const X = 1 16 | static var sx 17 | @export_group("Foo") 18 | @export var k = 1 19 | var x = 1 20 | var _x = 1 21 | @onready var y = null 22 | @onready var _y = null 23 | class Z: 24 | pass 25 | extends Node 26 | func foo(): 27 | pass 28 | """, 29 | ]) 30 | def test_class_definitions_order_ok(code): 31 | simple_ok_check(code, disable="unnecessary-pass") 32 | 33 | 34 | @pytest.mark.parametrize('code', [ 35 | """var x 36 | signal s 37 | """, 38 | """extends Node;var x 39 | signal s 40 | """, 41 | """ 42 | class X: var x;extends Node 43 | """, 44 | """var _x 45 | var x 46 | """, 47 | """@onready var x 48 | var y 49 | """, 50 | """@onready var _x 51 | @onready var x 52 | """, 53 | """var x 54 | enum X { A, B } 55 | """, 56 | """var x 57 | class_name Asdf 58 | """, 59 | """var x 60 | const X = 1 61 | """, 62 | """var x 63 | @tool 64 | """, 65 | """static func foo(): pass 66 | var x 67 | """, 68 | """'docstring' 69 | extends Node 70 | """, 71 | ]) 72 | def test_class_definitions_order_nok(code): 73 | simple_nok_check(code, 'class-definitions-order') 74 | -------------------------------------------------------------------------------- /tests/gd2py/test_conversion.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | from gdtoolkit.gd2py import convert_code 4 | 5 | 6 | VALID_SCRIPT_DIRS = [ 7 | "../formatter/big-input-files", 8 | "../formatter/input-output-pairs", 9 | "../valid-gd-scripts", 10 | ] 11 | EXCEPTIONS = [ 12 | "bug_326_multistatement_lambda_corner_case.out.gd", 13 | ] 14 | 15 | 16 | def pytest_generate_tests(metafunc): 17 | this_directory = os.path.dirname(os.path.abspath(__file__)) 18 | if "gdscript_path" in metafunc.fixturenames: 19 | valid_script_paths = set() 20 | for directory_relative_path in VALID_SCRIPT_DIRS: 21 | directory_absolute_path = os.path.join( 22 | this_directory, directory_relative_path 23 | ) 24 | valid_script_paths = valid_script_paths.union( 25 | set( 26 | os.path.join(directory_absolute_path, f) 27 | for f in os.listdir(directory_absolute_path) 28 | ) 29 | ) 30 | metafunc.parametrize("gdscript_path", valid_script_paths) 31 | 32 | 33 | def test_conversion_success(gdscript_path): 34 | if any(exception in gdscript_path for exception in EXCEPTIONS): 35 | return 36 | with open(gdscript_path, "r", encoding="utf-8") as file_handle: 37 | code = file_handle.read() 38 | convert_code(code) 39 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_boolean_test_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var a = ( 4 | "xxxxxxxxxxxxxxxxxxxxxxxxxxx" 5 | > "zzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzzz" 6 | ) 7 | var b = ( 8 | [1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 9 | in [1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1] 10 | ) 11 | var c = not not not not not not not not not not not not not not not not not not not not !true 12 | var d = ( 13 | true 14 | && true 15 | && true 16 | && true 17 | && true 18 | && true 19 | and true 20 | and true 21 | and true 22 | and true 23 | and true 24 | ) 25 | var e = ( 26 | true 27 | || true 28 | or true 29 | or true 30 | or true 31 | or true 32 | or true 33 | or true 34 | or true 35 | or true 36 | or true 37 | or true 38 | or true 39 | or true 40 | or 1 > 1111 41 | ) 42 | var f = ( 43 | "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx" 44 | if true 45 | else "yyyyyyyyyyyyyyyyyyyyyyyyyyyyy" 46 | ) 47 | var g = ( 48 | ( 49 | 1 50 | + 1 51 | + 1 52 | + 1 53 | + 1 54 | + 1 55 | + 1 56 | + 1 57 | + 1 58 | + 1 59 | + 1 60 | + 1 61 | + 1 62 | + 1 63 | + 1 64 | + 1 65 | + 1 66 | + 1 67 | + 1 68 | + 1 69 | + 1 70 | + 1 71 | + 1 72 | + 1 73 | ) 74 | + 1 75 | ) 76 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/properties.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | var p1: 4 | set(value): 5 | pass 6 | get: 7 | pass 8 | 9 | var p2 : int = 1: 10 | get: pass;pass;return 1 11 | set(value): pass;pass 12 | 13 | var p3: 14 | get = __get, 15 | set = __set 16 | 17 | var p4: 18 | set = __set, 19 | get = __get 20 | 21 | var p5: 22 | get = __get, set = __set 23 | 24 | var p6: 25 | set = __set, get = __get 26 | 27 | #var p7: 28 | # set(v): 29 | # pass 30 | # get = __get 31 | 32 | var p8: 33 | set = __set 34 | 35 | var p9: set = __set 36 | var p10: set = __set, get = __get 37 | #var p11: get: return 1 38 | 39 | func __get(): 40 | return 1 41 | 42 | func __set(v): 43 | pass 44 | 45 | class Foo: 46 | var p1: 47 | set(value): 48 | pass 49 | get: 50 | pass 51 | 52 | var p2 = 1: 53 | get: pass;pass 54 | set(value): pass;pass 55 | 56 | var p3: 57 | get = __get, 58 | set = __set 59 | 60 | var p4: 61 | set = __set, 62 | get = __get 63 | 64 | var p5: 65 | get = __get, set = __set 66 | 67 | var p6: 68 | set = __set, get = __get 69 | 70 | #var p7: 71 | # set(v): 72 | # pass 73 | # get = __get 74 | 75 | var p8: 76 | set = __set 77 | 78 | var p9: set = __set 79 | var p10: set = __set, get = __get 80 | #var p11: get: return 1 81 | 82 | func __get(): 83 | return 1 84 | 85 | func __set(v): 86 | pass 87 | 88 | var p11: 89 | set(value): 90 | pass 91 | get(): 92 | pass 93 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/complex_function_definitions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo( 3 | a = [ 4 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" 5 | ] 6 | ): 7 | pass 8 | 9 | func bar( 10 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb 11 | ): 12 | pass 13 | 14 | func baz( 15 | a = [ 16 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" 17 | ], 18 | b = [] 19 | ): 20 | pass 21 | 22 | func bax( 23 | a, 24 | b := [ 25 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" 26 | ] 27 | ): 28 | pass 29 | 30 | func bac( 31 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 32 | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: int 33 | ): 34 | pass 35 | 36 | func bav( 37 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 38 | bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb: Array = [ 39 | "aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa", "bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb" 40 | ] 41 | ): 42 | pass 43 | 44 | func bab( 45 | aaaaaaaaaaaaaaaaaaaaaaaaaaaaa, 46 | bbbbbbbbbbbbbbbbbbbbbbb, 47 | ccccccccccccccccccccc, 48 | ddddddddddddddd, 49 | ): 50 | pass 51 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/or_xor_and_shift_bitwise_expressions.out.gd: -------------------------------------------------------------------------------- 1 | class X: 2 | func foo(): 3 | var a = 1 << 2 >> 3 4 | var b = 1 & 1 & 1 5 | var c = 1 ^ 1 ^ 1 6 | var d = 1 | 1 | 1 7 | var q = ( 8 | 1 9 | << 1 10 | << 1 11 | << 1 12 | << 1 13 | << 1 14 | << 1 15 | << 1 16 | << 1 17 | << 1 18 | << 1 19 | << 1 20 | << 1 21 | << 1 22 | << 1 23 | << 1 24 | << 1 25 | << 1 26 | << 1 27 | << 1 28 | << 1 29 | ) 30 | var w = ( 31 | 1 32 | & 1 33 | & 1 34 | & 1 35 | & 1 36 | & 1 37 | & 1 38 | & 1 39 | & 1 40 | & 1 41 | & 1 42 | & 1 43 | & 1 44 | & 1 45 | & 1 46 | & 1 47 | & 1 48 | & 1 49 | & 1 50 | & 1 51 | & 1 52 | & 1 53 | & 1 54 | ) 55 | var e = ( 56 | 1 57 | ^ 1 58 | ^ 1 59 | ^ 1 60 | ^ 1 61 | ^ 1 62 | ^ 1 63 | ^ 1 64 | ^ 1 65 | ^ 1 66 | ^ 1 67 | ^ 1 68 | ^ 1 69 | ^ 1 70 | ^ 1 71 | ^ 1 72 | ^ 1 73 | ^ 1 74 | ^ 1 75 | ^ 1 76 | ^ 1 77 | ^ 1 78 | ^ 1 79 | ) 80 | var r = ( 81 | 1 82 | | 1 83 | | 1 84 | | 1 85 | | 1 86 | | 1 87 | | 1 88 | | 1 89 | | 1 90 | | 1 91 | | 1 92 | | 1 93 | | 1 94 | | 1 95 | | 1 96 | | 1 97 | | 1 98 | | 1 99 | | 1 100 | | 1 101 | | 1 102 | | 1 103 | | 1 104 | ) 105 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/inline_lambdas_w_comments.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | # a 3 | var x1 = func(): pass # inline a 4 | # b 5 | var x2 = func( 6 | p1, 7 | p2, 8 | p3, 9 | p4, 10 | p5, 11 | p6, 12 | p7, 13 | p8, 14 | p9, 15 | p10, 16 | p11, 17 | p12, 18 | p13, 19 | p14, 20 | p15, 21 | p16, 22 | p17, 23 | p18, 24 | p19, 25 | p20, 26 | p21, 27 | p22, 28 | p23 29 | ): 30 | pass # inline b 31 | # c 32 | var x3 = func baz( # inline c 33 | # d 34 | p1, # inline d 35 | # e 36 | p2, 37 | p3, 38 | p4, 39 | p5, 40 | p6, 41 | p7, 42 | p8, 43 | p9, 44 | p10, 45 | p11, 46 | p12, 47 | p13, 48 | p14, 49 | p15, 50 | p16, 51 | p17, 52 | p18, 53 | p19, 54 | p20, 55 | p21, 56 | p22, 57 | p23 # inline e 58 | # f 59 | ) -> int: 60 | pass 61 | pass 62 | var x := [ # inline f 63 | # g 64 | 0, # inline g 65 | # h 66 | 0, 67 | 0, 68 | 0, 69 | 0, 70 | 0, 71 | 0, 72 | 0, 73 | 0, 74 | 0, 75 | 0, 76 | 0, 77 | 0, 78 | 0, 79 | 0, 80 | 0, 81 | 0, 82 | 0, 83 | 0, 84 | 0, 85 | 0, 86 | 0, 87 | 0, 88 | 0, 89 | 0, 90 | 0, 91 | 0, 92 | 0, 93 | 0, 94 | 0, 95 | 0, 96 | 0, 97 | 0, 98 | 0, 99 | 0, 100 | 0, 101 | 0, 102 | 0, 103 | 0 # inline h 104 | # i 105 | ] 106 | pass # inline i 107 | # j 108 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/await.gd: -------------------------------------------------------------------------------- 1 | extends Node 2 | 3 | func coroutine(): 4 | print('coroutine(): 1 #', get_tree().get_frame()) 5 | await get_tree().process_frame 6 | print('coroutine(): 2 #', get_tree().get_frame()) 7 | await get_tree().process_frame 8 | print('coroutine(): 3 #', get_tree().get_frame()) 9 | return 1 10 | 11 | 12 | func fw_coroutine(): 13 | print('fw_coroutine(): 1 #', get_tree().get_frame()) 14 | var x = int(await coroutine() is int) + 1 15 | print(x) 16 | print('fw_coroutine(): 2 #', get_tree().get_frame()) 17 | 18 | 19 | func coroutine2(): 20 | print('coroutine2(): 1 #', get_tree().get_frame()) 21 | await get_tree().process_frame 22 | print('coroutine2(): 2 #', get_tree().get_frame()) 23 | await get_tree().process_frame 24 | print('coroutine2(): 3 #', get_tree().get_frame()) 25 | return get_tree().process_frame 26 | 27 | 28 | func fw_coroutine2(): 29 | print('fw_coroutine2(): 1 #', get_tree().get_frame()) 30 | await await coroutine2() 31 | print('fw_coroutine2(): 2 #', get_tree().get_frame()) 32 | 33 | 34 | func _ready(): 35 | print('_ready(): 1 #', get_tree().get_frame()) 36 | fw_coroutine() 37 | fw_coroutine2() 38 | print('_ready(): 2 #', get_tree().get_frame()) 39 | 40 | # outcome: 41 | 42 | # _ready(): 1 #0 43 | # fw_coroutine(): 1 #0 44 | # coroutine(): 1 #0 45 | # fw_coroutine2(): 1 #0 46 | # coroutine2(): 1 #0 47 | # _ready(): 2 #0 48 | # coroutine(): 2 #8 49 | # coroutine2(): 2 #8 50 | # coroutine(): 3 #9 51 | # 2 52 | # fw_coroutine(): 2 #9 53 | # coroutine2(): 3 #9 54 | # fw_coroutine2(): 2 #9 55 | -------------------------------------------------------------------------------- /tests/formatter/test_input_output_pairs.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import Set 3 | 4 | from .common import format_and_compare 5 | 6 | 7 | DATA_DIR = "./input-output-pairs" 8 | EXCEPTIONS = set( 9 | [ 10 | # TODO: fix 11 | "inline_lambdas_w_comments", 12 | # Desired yet not possible to support due to Godot bug: 13 | "bug_326_multistatement_lambda_corner_case", 14 | ] 15 | ) # type: Set[str] 16 | 17 | 18 | def pytest_generate_tests(metafunc): 19 | this_directory = os.path.dirname(os.path.abspath(__file__)) 20 | if "test_name" in metafunc.fixturenames: 21 | tests_in_dir = os.path.join(this_directory, DATA_DIR) 22 | metafunc.parametrize( 23 | "test_name", 24 | set( 25 | f.split(".")[0] 26 | for f in os.listdir(tests_in_dir) 27 | if f.split(".")[0] not in EXCEPTIONS 28 | ), 29 | ) 30 | 31 | 32 | def test_input_output_pair(test_name): 33 | this_dir = os.path.dirname(os.path.abspath(__file__)) 34 | input_file_path = os.path.join(this_dir, DATA_DIR, "{}.in.gd".format(test_name)) 35 | output_file_path = os.path.join(this_dir, DATA_DIR, "{}.out.gd".format(test_name)) 36 | with open(input_file_path, "r", encoding="utf-8") as input_handle: 37 | with open(output_file_path, "r", encoding="utf-8") as output_handle: 38 | input_code = input_handle.read() 39 | expected_output_code = output_handle.read() 40 | format_and_compare(input_code, expected_output_code) 41 | -------------------------------------------------------------------------------- /stubs/lark/__init__.pyi: -------------------------------------------------------------------------------- 1 | from typing import Any, List, Optional, Union, Iterator, Callable 2 | from lark.tree import Meta 3 | 4 | Node = Any # TODO: use one from gdtoolkit and fix accordingly 5 | 6 | Discard: Exception 7 | 8 | class Token(str): 9 | type: str 10 | line: int 11 | value: Any # TODO: remove and fix accordingly 12 | column: int 13 | end_line: int 14 | end_column: int 15 | def __init__( 16 | self, 17 | type_: str, 18 | value: str, 19 | line: int = ..., 20 | column: int = ..., 21 | end_line: int = ..., 22 | end_column: int = ..., 23 | ): ... 24 | 25 | class Tree: 26 | children: List[Node] 27 | line: int 28 | value: Any # TODO: remove and fix accordingly 29 | column: int 30 | end_line: int 31 | data: str 32 | meta: Meta 33 | def __init__(self, name: str, children: List[Node], meta: Optional[Meta] = ...): ... 34 | def iter_subtrees(self): ... 35 | def find_pred( 36 | self, pred: Callable[[Tree], bool] 37 | ) -> Iterator[Tree]: ... 38 | def find_data(self, data: str) -> Iterator[Tree]: ... 39 | def pretty(self, indent_str: str = ...) -> str: ... 40 | 41 | class Lark: 42 | def __init__(self, grammar: Any, **options): ... 43 | @classmethod 44 | def open( 45 | cls: Any, grammar_filename: str, rel_to: Optional[str] = ..., **options 46 | ) -> Lark: ... 47 | 48 | class UnexpectedInput: ... 49 | 50 | class Transformer: 51 | def transform(self, tree: Tree) -> Tree: ... 52 | 53 | __version__: str 54 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_unistatement_lambdas.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var x1 = func(): pass 3 | var x2 = func() -> int: return 1 4 | var x3 = func baz() -> int: return 1 5 | var x5 = func(): 1 6 | var x6 = func baz(): pass 7 | var x7 = func(): var x 8 | var x8 = func(): var x = 1 9 | var x9 = func(): var x: int 10 | var x10 = func(): var x: int = 1 11 | var x11 = func(): var x := 1 12 | var x12 = func(): breakpoint 13 | var x13 = func(): const foo = 1 14 | var x13a = func(): const foo: int = 1 15 | var x13b = func(): const foo := 1 16 | # TODO: fix 17 | # var x14 = func(): if true: pass 18 | # var x15 = func(): while false: pass 19 | # var x16 = func(): for x in [1]: pass 20 | # var x17 = func(): for x : int in [1]: pass 21 | pass 22 | 23 | 24 | func bar(): 25 | var x1 = func(): pass 26 | var x2 = func() -> int: return 1 27 | var x3 = func baz() -> int: return 1 28 | var x5 = func(): 1 29 | var x6 = func baz(): pass 30 | var x7 = func(): var x 31 | var x8 = func(): var x = 1 32 | var x9 = func(): var x: int 33 | var x10 = func(): var x: int = 1 34 | var x11 = func(): var x := 1 35 | var x12 = func(): breakpoint 36 | var x13 = func(): const foo = 1 37 | var x13a = func(): const foo: int = 1 38 | var x13b = func(): const foo := 1 39 | var x14 = func(): 40 | if true: 41 | pass 42 | var x15 = func(): 43 | while false: 44 | pass 45 | var x16 = func(): 46 | for x in [1]: 47 | pass 48 | var x17 = func(): 49 | for x: int in [1]: 50 | pass 51 | var x18 = func(): 52 | match 1: 53 | _: 54 | pass 55 | pass 56 | -------------------------------------------------------------------------------- /tests/gd2py/test_input_output_pairs.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import difflib 4 | 5 | from gdtoolkit.gd2py import convert_code 6 | 7 | 8 | DATA_DIR = "./input-output-pairs" 9 | 10 | 11 | def pytest_generate_tests(metafunc): 12 | this_directory = os.path.dirname(os.path.abspath(__file__)) 13 | if "test_name" in metafunc.fixturenames: 14 | tests_in_dir = os.path.join(this_directory, DATA_DIR) 15 | metafunc.parametrize( 16 | "test_name", set(f.split(".")[0] for f in os.listdir(tests_in_dir)) 17 | ) 18 | 19 | 20 | def test_input_output_pair(test_name): 21 | this_dir = os.path.dirname(os.path.abspath(__file__)) 22 | input_file_path = os.path.join(this_dir, DATA_DIR, "{}.in.gd".format(test_name)) 23 | output_file_path = os.path.join(this_dir, DATA_DIR, "{}.out.py".format(test_name)) 24 | with open(input_file_path, "r", encoding="utf-8") as input_handle: 25 | with open(output_file_path, "r", encoding="utf-8") as output_handle: 26 | input_code = input_handle.read() 27 | expected_output_code = output_handle.read() 28 | _convert_and_compare(input_code, expected_output_code) 29 | 30 | 31 | def _convert_and_compare(input_code, expected_output_code): 32 | converted_code = convert_code(input_code) 33 | _compare(converted_code, expected_output_code) 34 | 35 | 36 | def _compare(input_code, expected_output_code): 37 | diff = "\n".join( 38 | difflib.unified_diff(expected_output_code.splitlines(), input_code.splitlines()) 39 | ) 40 | assert input_code == expected_output_code, diff 41 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/simple_unistatement_lambdas.in.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | var x1 = func(): pass 3 | var x2 = func() -> int: return 1 4 | var x3 = func baz() -> int: return 1 5 | var x5 = func(): 1 6 | var x6 = func baz(): pass 7 | var x7 = func(): var x 8 | var x8 = func(): var x=1 9 | var x9 = func(): var x:int 10 | var x10 = func(): var x:int=1 11 | var x11 = func(): var x:=1 12 | var x12 = func(): breakpoint 13 | var x13 = func(): const foo =1 14 | var x13a = func(): const foo:int =1 15 | var x13b = func(): const foo:=1 16 | # TODO: fix 17 | # var x14 = func(): if true: pass 18 | # var x15 = func(): while false: pass 19 | # var x16 = func(): for x in [1]: pass 20 | # var x17 = func(): for x : int in [1]: pass 21 | pass 22 | 23 | func bar(): 24 | var x1 = func(): 25 | pass 26 | var x2 = func() -> int: 27 | return 1 28 | var x3 = func baz() -> int: 29 | return 1 30 | var x5 = func(): 31 | 1 32 | var x6 = func baz(): 33 | pass 34 | var x7 = func(): 35 | var x 36 | var x8 = func(): 37 | var x=1 38 | var x9 = func(): 39 | var x:int 40 | var x10 = func(): 41 | var x:int=1 42 | var x11 = func(): 43 | var x:=1 44 | var x12 = func(): 45 | breakpoint 46 | var x13 = func(): 47 | const foo =1 48 | var x13a = func(): 49 | const foo:int =1 50 | var x13b = func(): 51 | const foo:=1 52 | var x14 = func(): 53 | if true: 54 | pass 55 | var x15 = func(): 56 | while false: 57 | pass 58 | var x16 = func(): 59 | for x in [1]: 60 | pass 61 | var x17 = func(): 62 | for x : int in [1]: 63 | pass 64 | var x18 = func(): 65 | match 1: 66 | _: 67 | pass 68 | pass 69 | -------------------------------------------------------------------------------- /tests/valid-gd-scripts/multiline_lambdas.gd: -------------------------------------------------------------------------------- 1 | func stack(x): 2 | pass 3 | func foo(source): 4 | stack(func(): 5 | print("foo") 6 | if source == 1: 7 | var x: = 1 8 | pass) 9 | stack(func(): 10 | if true: 11 | pass 12 | if false: 13 | pass) 14 | var f0 = func bar(): 15 | pass 16 | var f1 = func(): 17 | pass 18 | var f11 = func(): 19 | var f11r = func(): 20 | pass 21 | var f12 = func(): 22 | var f12r = func(): 23 | return func(): pass 24 | var f13 = func(): 25 | pass 26 | var f13r = func(): 27 | pass 28 | return func(): pass 29 | var f14 = func(): 30 | pass 31 | var f14r = func(): 32 | if true: 33 | pass 34 | var f15 = func(): 35 | pass 36 | var f15r = func(): 37 | if true: 38 | pass 39 | pass 40 | pass 41 | var f16 = func(): 42 | pass 43 | @warning_ignore("unused_variable") 44 | var f17 = func(): 45 | @warning_ignore("unused_variable") 46 | var x 47 | var f18 = func(): 48 | @warning_ignore("unused_variable") var x 49 | var f19 = func(): 50 | @warning_ignore("unused_variable") @warning_ignore("unused_variable") var x 51 | var f2s = [func(): 52 | pass 53 | ] 54 | var f3s = [func(): 55 | pass 56 | pass 57 | ] 58 | var f4s = [func(): 59 | pass] 60 | var f5s = [func(): 61 | pass 62 | pass] 63 | var f6s = [func(): 64 | pass, func(): 65 | pass] 66 | var f7s = [func(): 67 | return [1,2,3], func(): 68 | pass] 69 | var f8s = [func(): 70 | pass 71 | var f8sr = func(): 72 | pass 73 | var dct = {'f':func(): 74 | pass 75 | var f8srr = func(): 76 | pass 77 | return [1,2,3]}] 78 | # Godot 4.3 failing: 79 | # var fx = func(): 80 | # pass if true else func(): 81 | # pass 82 | # var fx = func(): 83 | # pass is int 84 | -------------------------------------------------------------------------------- /tests/parser/test_parser.py: -------------------------------------------------------------------------------- 1 | import os 2 | 3 | import pytest 4 | from gdtoolkit.parser import parser 5 | 6 | 7 | OK_DATA_DIRS = [ 8 | "../valid-gd-scripts", 9 | "../formatter/input-output-pairs", 10 | ] 11 | NOK_DATA_DIR = "../invalid-gd-scripts" 12 | 13 | 14 | def pytest_generate_tests(metafunc): 15 | this_directory = os.path.dirname(os.path.abspath(__file__)) 16 | if "gdscript_ok_path" in metafunc.fixturenames: 17 | tests = [] 18 | for ok_data_dir in OK_DATA_DIRS: 19 | directory_tests = os.path.join(this_directory, ok_data_dir) 20 | tests += [ 21 | os.path.join(directory_tests, f) for f in os.listdir(directory_tests) 22 | ] 23 | metafunc.parametrize("gdscript_ok_path", tests) 24 | if "gdscript_nok_path" in metafunc.fixturenames: 25 | directory_tests = os.path.join(this_directory, NOK_DATA_DIR) 26 | metafunc.parametrize( 27 | "gdscript_nok_path", 28 | [os.path.join(directory_tests, f) for f in os.listdir(directory_tests)], 29 | ) 30 | 31 | 32 | @pytest.mark.parser 33 | def test_parsing_success(gdscript_ok_path): 34 | # TODO: fix lexer 35 | if "bug_326_multistatement_lambda_corner_case" in gdscript_ok_path: 36 | return 37 | with open(gdscript_ok_path, "r", encoding="utf-8") as handle: 38 | code = handle.read() 39 | parser.parse(code) # just checking if not throwing 40 | 41 | 42 | @pytest.mark.parser 43 | def test_parsing_failure(gdscript_nok_path): 44 | with open(gdscript_nok_path, "r", encoding="utf-8") as handle: 45 | code = handle.read() 46 | try: 47 | parser.parse(code) 48 | except: # pylint: disable=bare-except 49 | return 50 | assert True, "shall fail" 51 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_multistatement_lambdas.out.gd: -------------------------------------------------------------------------------- 1 | func xyz(x): 2 | pass 3 | 4 | 5 | func foo(): 6 | var x1 = func( 7 | p1, 8 | p2, 9 | p3, 10 | p4, 11 | p5, 12 | p6, 13 | p7, 14 | p8, 15 | p9, 16 | p10, 17 | p11, 18 | p12, 19 | p13, 20 | p14, 21 | p15, 22 | p16, 23 | p17, 24 | p18, 25 | p19, 26 | p20, 27 | p21, 28 | p22, 29 | p23 30 | ) -> int: 31 | var a = [ 32 | 1, 33 | 1, 34 | 1, 35 | 1, 36 | 1, 37 | 1, 38 | 1, 39 | 1, 40 | 1, 41 | 1, 42 | 1, 43 | 1, 44 | 1, 45 | 1, 46 | 1, 47 | 1, 48 | 1, 49 | 1, 50 | 1, 51 | 1, 52 | 1, 53 | 1, 54 | 1, 55 | 1, 56 | 1, 57 | 1, 58 | 1, 59 | 1, 60 | 1, 61 | 1, 62 | 1, 63 | 1, 64 | 1, 65 | 1, 66 | 1, 67 | 1, 68 | 1, 69 | 1, 70 | 1, 71 | 1, 72 | 1, 73 | 1, 74 | 1, 75 | 1, 76 | 1, 77 | 1, 78 | 1, 79 | 1 80 | ] 81 | var b = len(a) + 1 82 | if a > 1: 83 | return 1 84 | return 2 85 | var x2 = func baz( 86 | p1, 87 | p2, 88 | p3, 89 | p4, 90 | p5, 91 | p6, 92 | p7, 93 | p8, 94 | p9, 95 | p10, 96 | p11, 97 | p12, 98 | p13, 99 | p14, 100 | p15, 101 | p16, 102 | p17, 103 | p18, 104 | p19, 105 | p20, 106 | p21, 107 | p22, 108 | p23 109 | ): 110 | var a = { 111 | "a1": 1, 112 | "a2": 1, 113 | "a3": 1, 114 | "a4": 1, 115 | "a5": 1, 116 | "a6": 1, 117 | "a7": 1, 118 | "a8": 1, 119 | "a9": 1, 120 | "a10": 1, 121 | "a11": 1, 122 | "a12": 1, 123 | "a13": 1, 124 | "a14": 1, 125 | "a15": 1, 126 | "a16": 1, 127 | "a17": 1 128 | } 129 | var b = [a["a1"], 1, 2, 3] 130 | for bb in b: 131 | break 132 | 133 | pass 134 | -------------------------------------------------------------------------------- /gdtoolkit/common/utils.py: -------------------------------------------------------------------------------- 1 | import os 2 | from typing import FrozenSet, List, Optional 3 | 4 | from lark import Tree, Token 5 | 6 | from .types import Node 7 | 8 | Path = str 9 | 10 | 11 | def find_gd_files_from_paths( 12 | paths: List[Path], excluded_directories: FrozenSet[Path] = frozenset() 13 | ) -> List[Path]: 14 | """Finds .gd files in directories recursively and combines results to the list""" 15 | files = [] 16 | for path in paths: 17 | if os.path.isdir(path): 18 | for dirpath, dirnames, filenames in os.walk(path, topdown=True): 19 | dirnames[:] = [d for d in dirnames if d not in excluded_directories] 20 | files += [ 21 | os.path.join(dirpath, f) for f in filenames if f.endswith(".gd") 22 | ] 23 | else: 24 | files.append(path) 25 | return files 26 | 27 | 28 | def find_name_token_among_children(tree: Tree) -> Optional[Token]: 29 | for child in tree.children: 30 | if isinstance(child, Token) and child.type in ["NAME", "GET", "SET"]: 31 | return child 32 | return None 33 | 34 | 35 | def find_tree_among_children(tree_name_to_find: str, tree: Tree) -> Optional[Tree]: 36 | for child in tree.children: 37 | if isinstance(child, Tree) and child.data == tree_name_to_find: 38 | return child 39 | return None 40 | 41 | 42 | # TODO: remove 43 | def get_line(node: Node) -> int: 44 | if isinstance(node, Tree): 45 | return node.meta.line 46 | return node.line 47 | 48 | 49 | # TODO: remove 50 | def get_end_line(node: Node) -> int: 51 | if isinstance(node, Tree): 52 | return node.meta.end_line 53 | return node.end_line 54 | 55 | 56 | # TODO: remove 57 | def get_column(node: Node) -> int: 58 | if isinstance(node, Tree): 59 | return node.meta.column 60 | return node.column 61 | -------------------------------------------------------------------------------- /gdtoolkit/formatter/const_statement.py: -------------------------------------------------------------------------------- 1 | from lark import Tree 2 | 3 | from ..common.utils import get_line, get_end_line 4 | from .types import Outcome 5 | from .context import Context, ExpressionContext 6 | from .expression import format_expression 7 | 8 | 9 | def format_const_statement(statement: Tree, context: Context) -> Outcome: 10 | concrete_const_stmt = statement.children[0] 11 | handlers = { 12 | "const_assigned": _format_const_assigned_statement, 13 | "const_typed_assigned": _format_const_typed_assigned_statement, 14 | "const_inf": _format_const_inferred_statement, 15 | } 16 | return handlers[concrete_const_stmt.data](concrete_const_stmt, context) 17 | 18 | 19 | def _format_const_assigned_statement(statement: Tree, context: Context) -> Outcome: 20 | expression_context = ExpressionContext( 21 | f"const {statement.children[0].value} = ", 22 | get_line(statement), 23 | "", 24 | get_end_line(statement), 25 | ) 26 | return format_expression(statement.children[-1], expression_context, context) 27 | 28 | 29 | def _format_const_typed_assigned_statement( 30 | statement: Tree, context: Context 31 | ) -> Outcome: 32 | expression_context = ExpressionContext( 33 | f"const {statement.children[0].value}: {statement.children[1].value} = ", 34 | get_line(statement), 35 | "", 36 | get_end_line(statement), 37 | ) 38 | return format_expression(statement.children[-1], expression_context, context) 39 | 40 | 41 | def _format_const_inferred_statement(statement: Tree, context: Context) -> Outcome: 42 | expression_context = ExpressionContext( 43 | f"const {statement.children[0].value} := ", 44 | get_line(statement), 45 | "", 46 | get_end_line(statement), 47 | ) 48 | return format_expression(statement.children[-1], expression_context, context) 49 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/long_unistatement_lambdas.in.gd: -------------------------------------------------------------------------------- 1 | func xyz(x): 2 | pass 3 | func foo(): 4 | 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 5 | 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 6 | 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 7 | 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 8 | 9 | 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] 10 | 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]) 11 | 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 12 | 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] 13 | 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 14 | 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] 15 | 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] 16 | -------------------------------------------------------------------------------- /tests/formatter/test_basics.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from .common import format_and_compare 4 | 5 | 6 | # fmt: off 7 | @pytest.mark.parametrize("input_code,expected_output_code", [ 8 | ("", ""), 9 | ( 10 | "pass", 11 | """pass 12 | """, 13 | ), 14 | ]) 15 | # fmt: on 16 | def test_formatting(input_code, expected_output_code): 17 | format_and_compare(input_code, expected_output_code) 18 | 19 | 20 | def test_indentation_using_tabs(): 21 | input_code = "\n".join( 22 | [ 23 | "extends Node", 24 | "func foo():", 25 | " if True:", 26 | " pass", 27 | " if False:", 28 | " while True:", 29 | " pass", 30 | ] 31 | ) 32 | expected_output_code = "\n".join( 33 | [ 34 | "extends Node", 35 | "", 36 | "", 37 | "func foo():", 38 | "\tif True:", 39 | "\t\tpass", 40 | "\tif False:", 41 | "\t\twhile True:", 42 | "\t\t\tpass", 43 | "", 44 | ] 45 | ) 46 | format_and_compare(input_code, expected_output_code) 47 | 48 | 49 | def test_indentation_using_spaces(): 50 | input_code = "\n".join( 51 | [ 52 | "extends Node", 53 | "func foo():", 54 | " if True:", 55 | " pass", 56 | " if False:", 57 | " while True:", 58 | " pass", 59 | ] 60 | ) 61 | expected_output_code = "\n".join( 62 | [ 63 | "extends Node", 64 | "", 65 | "", 66 | "func foo():", 67 | " if True:", 68 | " pass", 69 | " if False:", 70 | " while True:", 71 | " pass", 72 | "", 73 | ] 74 | ) 75 | format_and_compare(input_code, expected_output_code, spaces_for_indent=3) 76 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | from setuptools import setup 2 | 3 | 4 | setup( 5 | name="gdtoolkit", 6 | version="4.5.1", 7 | description="Independent set of tools for working with GDScript - parser, linter and formatter", 8 | keywords=["GODOT", "GDSCRIPT", "PARSER", "LINTER", "FORMATTER"], 9 | url="https://github.com/Scony/godot-gdscript-toolkit", 10 | author="Pawel Lampe", 11 | author_email="pawel.lampe@gmail.com", 12 | license="MIT", 13 | packages=[ 14 | "gdtoolkit", 15 | "gdtoolkit.linter", 16 | "gdtoolkit.formatter", 17 | "gdtoolkit.parser", 18 | "gdtoolkit.common", 19 | "gdtoolkit.gd2py", 20 | "gdtoolkit.gdradon", 21 | ], 22 | package_data={"gdtoolkit.parser": ["gdscript.lark", "comments.lark"]}, 23 | entry_points={ 24 | "console_scripts": [ 25 | "gdparse = gdtoolkit.parser.__main__:main", 26 | "gdlint = gdtoolkit.linter.__main__:main", 27 | "gdformat = gdtoolkit.formatter.__main__:main", 28 | "gd2py = gdtoolkit.gd2py.__main__:main", 29 | "gdradon = gdtoolkit.gdradon.__main__:main", 30 | ] 31 | }, 32 | include_package_data=True, 33 | install_requires=[ 34 | "lark[regex]==1.2.2", 35 | "docopt-ng==0.9.0", 36 | "pyyaml>=5.1", 37 | "radon==6.0.1", 38 | "setuptools", 39 | ], 40 | python_requires=">=3.7", 41 | classifiers=[ 42 | "Development Status :: 5 - Production/Stable", 43 | "Intended Audience :: Developers", 44 | "License :: OSI Approved :: MIT License", 45 | "Programming Language :: Python :: 3", 46 | "Programming Language :: Python :: 3.7", 47 | "Programming Language :: Python :: 3.8", 48 | "Programming Language :: Python :: 3.9", 49 | "Programming Language :: Python :: 3.10", 50 | "Topic :: Software Development :: Libraries :: Python Modules", 51 | ], 52 | ) 53 | -------------------------------------------------------------------------------- /tests/linter/test_gdlint_ignore.py: -------------------------------------------------------------------------------- 1 | import pytest 2 | 3 | from .common import simple_ok_check, simple_nok_check 4 | 5 | 6 | # fmt: off 7 | @pytest.mark.parametrize('code', [ 8 | """ 9 | # gdlint: ignore=function-name 10 | func some_Button_pressed(): 11 | pass 12 | """, 13 | """ 14 | # gdlint:ignore = function-name 15 | func SomeName(): 16 | pass 17 | """, 18 | """ 19 | # gdlint:ignore = function-name, function-argument-name 20 | func SomeName(someArg): 21 | assert(someArg > 0) 22 | """, 23 | """ 24 | # gdlint:ignore = function-name , function-argument-name 25 | func SomeName(someArg): 26 | assert(someArg > 0) 27 | """, 28 | """ 29 | # gdlint:ignore = function-name ,function-argument-name 30 | func SomeName(someArg): 31 | assert(someArg > 0) 32 | """, 33 | ]) 34 | def test_linting_ok_when_problem_ignored(code): 35 | simple_ok_check(code) 36 | 37 | 38 | @pytest.mark.parametrize('code', [ 39 | """ 40 | # gdlint: disable=function-name 41 | func some_Button_pressed(): 42 | pass 43 | """, 44 | """# gdlint: disable=max-public-methods 45 | func f0(): pass 46 | func f1(): pass 47 | func f2(): pass 48 | func f3(): pass 49 | func f4(): pass 50 | func f5(): pass 51 | func f6(): pass 52 | func f7(): pass 53 | func f8(): pass 54 | func f9(): pass 55 | func f10(): pass 56 | func f11(): pass 57 | func f12(): pass 58 | func f13(): pass 59 | func f14(): pass 60 | func f15(): pass 61 | func f16(): pass 62 | func f17(): pass 63 | func f18(): pass 64 | func f19(): pass 65 | func f20(): pass 66 | """, 67 | ]) 68 | def test_linting_ok_when_problem_disabled(code): 69 | simple_ok_check(code) 70 | 71 | 72 | @pytest.mark.parametrize('code', [ 73 | """ 74 | # gdlint: disable=function-name 75 | func some_Button_pressed(): 76 | pass 77 | # gdlint: enable=function-name 78 | func some_Button_pressed(): 79 | pass 80 | """, 81 | ]) 82 | def test_linting_nok_when_problem_enabled_again(code): 83 | simple_nok_check(code, check_name='function-name', line=6) 84 | -------------------------------------------------------------------------------- /gdtoolkit/formatter/__init__.py: -------------------------------------------------------------------------------- 1 | from typing import Optional 2 | 3 | from types import MappingProxyType 4 | from lark import Tree 5 | 6 | from ..parser import parser 7 | from .formatter import format_code # noqa: F401 8 | from .safety_checks import ( # noqa: F401 9 | check_tree_invariant, 10 | check_formatting_stability, 11 | check_comment_persistence, 12 | LoosenTreeTransformer, 13 | ) 14 | 15 | DEFAULT_CONFIG = MappingProxyType( 16 | { 17 | "excluded_directories": {".git"}, 18 | "safety_checks": None, 19 | "use_spaces": None, 20 | "line_length": 100, 21 | } 22 | ) 23 | 24 | 25 | # pylint: disable-next=too-many-arguments 26 | # pylint: disable=too-many-positional-arguments 27 | # pylint: disable=too-many-arguments 28 | def check_formatting_safety( 29 | given_code: str, 30 | formatted_code: str, 31 | max_line_length: int, 32 | given_code_parse_tree: Optional[Tree] = None, 33 | given_code_comment_parse_tree: Optional[Tree] = None, 34 | spaces_for_indent: Optional[int] = None, 35 | ) -> None: 36 | if given_code == formatted_code: 37 | return 38 | formatted_code_parse_tree = parser.parse(formatted_code, gather_metadata=True) 39 | formatted_code_comment_parse_tree = parser.parse_comments(formatted_code) 40 | check_comment_persistence( 41 | given_code, 42 | formatted_code, 43 | given_code_comment_parse_tree=given_code_comment_parse_tree, 44 | formatted_code_comment_parse_tree=formatted_code_comment_parse_tree, 45 | ) 46 | check_tree_invariant( 47 | given_code, 48 | formatted_code, 49 | given_code_parse_tree=given_code_parse_tree, 50 | formatted_code_parse_tree=formatted_code_parse_tree, 51 | ) 52 | check_formatting_stability( 53 | formatted_code, 54 | max_line_length, 55 | parse_tree=formatted_code_parse_tree, 56 | comment_parse_tree=formatted_code_comment_parse_tree, 57 | spaces_for_indent=spaces_for_indent, 58 | ) 59 | -------------------------------------------------------------------------------- /tests/formatter/input-output-pairs/type_cast_corner_case_expressions.out.gd: -------------------------------------------------------------------------------- 1 | func foo(): 2 | 1 as int or [1, 2] == [1, 2] 3 | ( 4 | 1 as int 5 | or ( 6 | [ 7 | 1, 8 | 2, 9 | ] 10 | == [ 11 | 1, 12 | 2, 13 | ] 14 | ) 15 | ) 16 | # --- 17 | 1 as int if true else 2 if true else 3 18 | ( 19 | 1 as int 20 | if true 21 | else ( 22 | 2 23 | if [ 24 | 1, 25 | ] 26 | else 3 27 | ) 28 | ) 29 | # --- 30 | 1 as int or true and true 31 | ( 32 | 1 as int 33 | or ( 34 | [ 35 | 1, 36 | ] 37 | and true 38 | ) 39 | ) 40 | # --- 41 | not 1 in [0] 42 | not ( 43 | 1 44 | in [ 45 | 0, 46 | ] 47 | ) 48 | # --- 49 | 1 as int if true or true else true 50 | ( 51 | 1 as int 52 | if ( 53 | [ 54 | 1, 55 | ] 56 | or true 57 | ) 58 | else true 59 | ) 60 | # --- 61 | 1 as int or 1 | 1 62 | ( 63 | 1 as int 64 | or ( 65 | [ 66 | 1, 67 | ] 68 | | 1 69 | ) 70 | ) 71 | # --- 72 | 1 as int or 1 ^ 1 73 | ( 74 | 1 as int 75 | or ( 76 | [ 77 | 1, 78 | ] 79 | ^ 1 80 | ) 81 | ) 82 | # --- 83 | 1 as int or 1 & 1 84 | ( 85 | 1 as int 86 | or ( 87 | [ 88 | 1, 89 | ] 90 | & 1 91 | ) 92 | ) 93 | # --- 94 | 1 as int or 1 << 1 95 | ( 96 | 1 as int 97 | or ( 98 | [ 99 | 1, 100 | ] 101 | << 1 102 | ) 103 | ) 104 | # --- 105 | 1 as int or 1 * 1 106 | ( 107 | 1 as int 108 | or ( 109 | [ 110 | 1, 111 | ] 112 | * 1 113 | ) 114 | ) 115 | # --- 116 | 1 as int or 1 + 1 117 | ( 118 | 1 as int 119 | or ( 120 | [ 121 | 1, 122 | ] 123 | - 1 124 | ) 125 | ) 126 | # --- 127 | 1 as int or 1 is int1 128 | ( 129 | 1 as int 130 | or ( 131 | [ 132 | 1, 133 | ] 134 | is Array 135 | ) 136 | ) 137 | # -- 138 | 1 as int or 1 ** 1 139 | ( 140 | 1 as int 141 | or ( 142 | [ 143 | 1, 144 | ] 145 | ** 2 146 | ) 147 | ) 148 | --------------------------------------------------------------------------------