diff --git a/jaclang/compiler/passes/tool/jac_formatter_pass.py b/jaclang/compiler/passes/tool/jac_formatter_pass.py index 4780096c9..6f9408de0 100644 --- a/jaclang/compiler/passes/tool/jac_formatter_pass.py +++ b/jaclang/compiler/passes/tool/jac_formatter_pass.py @@ -126,11 +126,14 @@ def exit_module(self, node: ast.Module) -> None: last_element = None for counter, i in enumerate(node.body): counter += 1 + if last_element and ( + i.loc.first_line - last_element.loc.last_line > 1 + and not last_element.gen.jac.endswith("\n\n") + ): + self.emit_ln(node, "") if isinstance(i, ast.Import): self.emit_ln(node, i.gen.jac) else: - if isinstance(last_element, ast.Import): - self.emit_ln(node, "") if last_element and ( isinstance(i, ast.Architype) and isinstance(last_element, ast.Architype) @@ -140,21 +143,6 @@ def exit_module(self, node: ast.Module) -> None: self.emit_ln(node, "") self.emit_ln(node, i.gen.jac) - if counter <= len(node.body) - 1: - if ( - isinstance(i, ast.Ability) - and isinstance(node.body[counter], ast.Ability) - and i.gen.jac.endswith(";") - or ( - isinstance(i, ast.Architype) - and len(node.body[counter].kid[-1].kid) == 2 - and len(node.body[counter - 1].kid[-1].kid) == 2 - ) - and node.gen.jac.endswith("\n") - ): - self.emit(node, "") - else: - self.emit_ln(node, "") last_element = i def exit_global_vars(self, node: ast.GlobalVars) -> None: @@ -222,6 +210,20 @@ def exit_sub_node_list(self, node: ast.SubNodeList) -> None: """ prev_token = None for stmt in node.kid: + line_emiited = False + if prev_token and stmt.loc.first_line - prev_token.loc.last_line > 1: + if ( + stmt.kid + and isinstance(stmt.kid[-1], ast.SubNodeList) + and not isinstance(stmt.kid[-1].kid[-1], ast.CommentToken) + ): + self.emit(node, "") + + else: + line_emiited = True + self.indent_level -= 1 + self.emit_ln(node, "") + self.indent_level += 1 if isinstance(node.parent, (ast.EnumDef, ast.Enum)) and stmt.gen.jac == ",": self.indent_level -= 1 self.emit_ln(node, f"{stmt.gen.jac}") @@ -266,9 +268,10 @@ def exit_sub_node_list(self, node: ast.SubNodeList) -> None: self.indent_level += 1 else: self.emit(node, f" {stmt.gen.jac}") - self.indent_level -= 1 - self.emit_ln(node, "") - self.indent_level += 1 + if not line_emiited: + self.indent_level -= 1 + self.emit_ln(node, "") + self.indent_level += 1 else: if not node.gen.jac.endswith("\n"): self.indent_level -= 1 @@ -280,11 +283,10 @@ def exit_sub_node_list(self, node: ast.SubNodeList) -> None: self.emit(node, f"{stmt.gen.jac}") else: self.emit(node, stmt.gen.jac) - if not stmt.gen.jac.endswith("postinit;"): - self.indent_level -= 1 - self.emit_ln(stmt, "") - self.emit_ln(node, "") - self.indent_level += 1 + self.indent_level -= 1 + self.emit_ln(stmt, "") + self.emit_ln(node, "") + self.indent_level += 1 elif stmt.gen.jac == ",": self.emit(node, f"{stmt.value} ") elif stmt.value == "=": @@ -304,10 +306,20 @@ def exit_sub_node_list(self, node: ast.SubNodeList) -> None: isinstance(prev_token, ast.Ability) and isinstance(stmt, (ast.Ability, ast.AbilityDef)) ): - if not isinstance(prev_token.kid[-1], ast.CommentToken): - self.indent_level -= 1 - self.emit_ln(node, "") - self.indent_level += 1 + if ( + not isinstance(prev_token.kid[-1], ast.CommentToken) + and not line_emiited + ): + if ( + prev_token.kid + and isinstance(prev_token.kid[-1], ast.SubNodeList) + and isinstance(prev_token.kid[-1].kid[-1], ast.CommentToken) + ): + self.emit(node, "") + else: + self.indent_level -= 1 + self.emit_ln(node, "") + self.indent_level += 1 self.emit(node, stmt.gen.jac) else: if prev_token and prev_token.gen.jac.strip() == "{": @@ -907,8 +919,6 @@ def is_line_break_needed(self, content: str, max_line_length: int = 0) -> bool: """Check if the length of the current generated code exceeds the max line length.""" if max_line_length == 0: max_line_length = self.MAX_LINE_LENGTH - # print(content) - # print(len(content)) return len(content) > max_line_length def exit_binary_expr(self, node: ast.BinaryExpr) -> None: @@ -958,7 +968,6 @@ def exit_binary_expr(self, node: ast.BinaryExpr) -> None: self.error( f"Binary operator {node.op.value} not supported in bootstrap Jac" ) - # print(node.gen) if isinstance( node.kid[-1], (ast.Semi, ast.CommentToken) ) and not node.gen.jac.endswith("\n"): diff --git a/jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/line_spacing.jac b/jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/line_spacing.jac new file mode 100644 index 000000000..8a2b5fec6 --- /dev/null +++ b/jaclang/compiler/passes/tool/tests/fixtures/general_format_checks/line_spacing.jac @@ -0,0 +1,50 @@ +import:py math; + +glob RAD = 5; +glob DIA = 10; + +walker decorator_walk { + can hash(func: Any) { + can inner(a: Any) { + print(("#" * 20)); + func(a); + print(("#" * 20)); + } + return inner; + } + + can exclaim(func: Any) { + can inner(b: Any) { + print(("!" * 20)); + func(b); + print(("!" * 20)); + } + return inner; + } + + can tilde(func: Any) { + can inner(c: Any) { + print(("~" * 20)); + func(c); + print(("~" * 20)); + } + return inner; + } + + can greeter(name: Any) { + print("Hello, " + name + "!"); + } + + # Entry point for the walker + can start with entry { + # Apply decorators to greeter + decorated_greeter = hash(exclaim(tilde(greeter))); + + # Call the decorated greeter function + decorated_greeter("World"); + } +} + +with entry { + root spawn decorator_walk(); +} diff --git a/jaclang/tests/test_language.py b/jaclang/tests/test_language.py index 893c93989..e286b91f7 100644 --- a/jaclang/tests/test_language.py +++ b/jaclang/tests/test_language.py @@ -522,7 +522,7 @@ def test_pyfunc_1(self) -> None: self.assertIn("can greet2(**kwargs: Any) {", output) self.assertIn("squares_dict = {x: (x ** 2) for x in numbers};", output) self.assertIn( - '\n\n@ my_decorator \n can say_hello() {\n """Say hello""" ; ', output + '\n\n@ my_decorator \n can say_hello() {\n\n """Say hello""" ;', output ) def test_needs_import_2(self) -> None: @@ -568,7 +568,7 @@ def test_pyfunc_2(self) -> None: py_ast.parse(f.read()), mod_path=py_out_path ), ).ir.unparse() - self.assertIn("class X {\n with entry {\n a_b = 67;", output) + self.assertIn("class X {\n with entry {\n\n a_b = 67;", output) self.assertIn("br = b'Hello\\\\\\\\nWorld'", output) self.assertIn("class Circle {\n can init(radius: float", output) self.assertIn("<>node = 90; \n print(<>node) ;\n}\n", output)