nitpretty: does not force `do` inlining on APropdefs anymore
[nit.git] / src / pretty.nit
index 3b3cb90..bc556ad 100644 (file)
 # See the License for the specific language governing permissions and
 # limitations under the License.
 
+# Library used to pretty print Nit code.
+#
+# Usage:
+#
+#     import parser_util
+#     var tc = new ToolContext
+#     var nmodule = tc.parse_something("class A\nfun   toto :  Int  do   return   5\nend")
+#     var ppv = new PrettyPrinterVisitor
+#     var pmodule = ppv.pretty(nmodule)
+#     assert pmodule.write_to_string == """
+#     class A
+#     \tfun toto: Int do return 5
+#     end"""
+#
+# See `nitpretty` tool for more documentation.
 module pretty
 
 import template
@@ -157,7 +172,7 @@ class PrettyPrinterVisitor
                else
                        abort
                end
-               assert current_token.location <= token.location
+               if current_token.location > token.location then return
                while current_token != token do visit current_token
        end
 
@@ -168,7 +183,7 @@ class PrettyPrinterVisitor
                        visit current_token
                end
 
-               while current_token isa TEol do skip
+               while current_token isa TEol do visit(current_token)
        end
 
        # The template under construction.
@@ -221,12 +236,19 @@ class PrettyPrinterVisitor
        # Add a space.
        fun adds do add " "
 
+       # Visit explicit receiver, implicit self will be ignored.
        fun visit_recv(n_expr: AExpr) do
                if not n_expr isa AImplicitSelfExpr then
                        visit n_expr
                        consume "."
                end
        end
+
+       # Do we break string literals that are too long?
+       var break_strings = false is public writable
+
+       # Do we force `do` to be on the same line as the method signature?
+       var inline_do = false is public writable
 end
 
 # Base framework redefs
@@ -240,8 +262,9 @@ redef class ANodes[E]
                                if not e_can_inline then
                                        v.add ","
                                        v.addn
+                                       v.indent += 1
                                        v.addt
-                                       v.addt
+                                       v.indent -= 1
                                else
                                        v.add ", "
                                end
@@ -328,7 +351,7 @@ redef class Prod
        end
 
        redef fun was_inline do
-               return first_token.location.line_start == last_token.location.line_end
+               return start_token.location.line_start == last_token.location.line_end
        end
 end
 
@@ -418,7 +441,6 @@ redef class AAnnotations
        redef fun accept_pretty_printer(v) do
                v.adds
                v.consume "is"
-
                if v.can_inline(self) then
                        v.adds
                        for n_item in n_items do
@@ -427,21 +449,21 @@ redef class AAnnotations
                                        v.add ", "
                                end
                        end
-                       v.finish_line
-               else if n_items.length > 1 then
+                       if not was_inline then
+                               v.finish_line
+                               if v.current_token isa TKwend then v.skip
+                       end
+               else
                        v.addn
                        v.indent += 1
-
                        for n_item in n_items do
                                v.addt
                                v.visit n_item
                                v.finish_line
-                               v.addn
+                               if n_item != n_items.last then v.addn
                        end
-
                        v.indent -= 1
                end
-               if not was_inline and v.current_token isa TKwend then v.skip
        end
 
        redef fun is_inlinable do
@@ -453,6 +475,10 @@ end
 
 redef class AAnnotation
        redef fun accept_pretty_printer(v) do
+               if n_visibility != null and not n_visibility isa APublicVisibility then
+                       v.visit n_visibility
+                       v.adds
+               end
                v.visit n_atid
                if not n_args.is_empty then
                        if n_opar == null then
@@ -756,6 +782,86 @@ redef class APropdef
                end
        end
 
+       # Factorize annotations visit for all APropdef.
+       #
+       # Return true if annotations were inlined.
+       fun visit_annotations(v: PrettyPrinterVisitor, n_annotations: nullable AAnnotations): Bool do
+               var res = v.can_inline(n_annotations)
+               if n_annotations != null then v.visit n_annotations
+               return res
+       end
+
+       # Factorize block visit for APropdefs.
+       #
+       # Were annotations printed inline? If so, we need to print the block differently.
+       fun visit_block(v: PrettyPrinterVisitor, n_block: nullable AExpr, annot_inline: Bool) do
+               var can_inline = v.can_inline(n_block)
+               if n_block == null then return
+               if n_annotations != null and not annot_inline then
+                       v.addn
+                       v.addt
+               end
+               if v.inline_do then
+                       while not v.current_token isa TKwdo do v.skip
+               end
+               var token = v.current_token
+               var do_inline = true
+               loop
+                       if token isa TEol then
+                               v.skip
+                               if not v.can_inline(n_block) then
+                                       v.addn
+                                       v.addt
+                                       do_inline = false
+                               end
+                       end
+                       token = v.current_token
+                       if token isa TKwdo then break
+               end
+               if annot_inline and do_inline then v.adds
+               v.consume "do"
+
+               if v.can_inline(n_block) and do_inline then
+                       v.adds
+
+                       if n_block isa ABlockExpr then
+                               if n_block.n_expr.is_empty then
+                                       v.visit n_block.n_kwend
+                               else
+                                       v.visit n_block.n_expr.first
+                                       v.current_token = n_block.n_kwend
+                                       v.skip
+                               end
+                       else
+                               v.visit n_block
+                               if v.current_token isa TKwend then v.skip
+                       end
+               else
+                       v.finish_line
+                       v.addn
+                       v.indent += 1
+
+                       if n_block isa ABlockExpr then
+                               n_block.force_block = true
+                               v.visit n_block
+                               v.catch_up n_block.n_kwend
+                       else
+                               v.addt
+                               v.visit n_block
+                               v.addn
+                       end
+
+                       v.indent -= 1
+                       v.addt
+                       if n_block isa ABlockExpr then
+                               v.visit n_block.n_kwend
+                       else
+                               v.add "end"
+                       end
+               end
+               v.finish_line
+       end
+
        redef fun start_token do
                if n_doc == null then return super
                return n_doc.last_token.next_token
@@ -782,7 +888,8 @@ redef class AAttrPropdef
                        v.visit n_expr
                end
 
-               if n_annotations != null then v.visit n_annotations
+               var annot_inline = visit_annotations(v, n_annotations)
+               visit_block(v, n_block, annot_inline)
                v.finish_line
                v.addn
        end
@@ -806,6 +913,7 @@ redef class ATypePropdef
                v.consume ":"
                v.adds
                v.visit n_type
+               visit_annotations(v, n_annotations)
                v.finish_line
                v.addn
        end
@@ -818,7 +926,6 @@ redef class AMethPropdef
                #  TODO: Handle extern annotations
 
                var before = v.indent
-               var can_inline = v.can_inline(self)
                super
                if n_kwinit != null then v.visit n_kwinit
                if n_kwmeth != null then v.visit n_kwmeth
@@ -831,72 +938,15 @@ redef class AMethPropdef
 
                v.visit n_signature
 
-               if n_annotations != null then
-                       v.visit n_annotations
-               else
-                       v.adds
-               end
+               var annot_inline = visit_annotations(v, n_annotations)
 
                if n_extern_calls != null or n_extern_code_block != null then
-                       if n_annotations != null then v.adds
+                       v.adds
                        if n_extern_calls != null then v.visit n_extern_calls
                        if n_extern_code_block != null then v.visit n_extern_code_block
                end
 
-               var n_block = self.n_block
-
-               if n_block != null then
-                       while not v.current_token isa TKwdo do v.skip
-                       if n_annotations != null then
-                               if v.can_inline(n_annotations) then
-                                       v.adds
-                               else
-                                       v.addt
-                               end
-                       end
-                       v.consume "do"
-
-                       if can_inline then
-                               v.adds
-
-                               if n_block isa ABlockExpr then
-                                       if n_block.n_expr.is_empty then
-                                               v.visit n_block.n_kwend
-                                       else
-                                               v.visit n_block.n_expr.first
-                                               v.current_token = n_block.n_kwend
-                                               v.skip
-                                       end
-                               else
-                                       v.visit n_block
-                                       if v.current_token isa TKwend then v.skip
-                               end
-                       else
-                               v.finish_line
-                               v.addn
-                               v.indent += 1
-
-                               if n_block isa ABlockExpr then
-                                       n_block.force_block = true
-                                       v.visit n_block
-                                       v.catch_up n_block.n_kwend
-                               else
-                                       v.addt
-                                       v.visit n_block
-                                       v.addn
-                               end
-
-                               v.indent -= 1
-                               v.addt
-                               if n_block isa ABlockExpr then
-                                       v.visit n_block.n_kwend
-                               else
-                                       v.add "end"
-                               end
-                       end
-               end
-
-               v.finish_line
+               visit_block(v, n_block, annot_inline)
                v.addn
                assert v.indent == before
        end
@@ -964,8 +1014,9 @@ redef class AExternCalls
                        v.visit_list n_extern_calls
                else
                        v.addn
+                       v.indent += 1
                        v.addt
-                       v.addt
+                       v.indent -= 1
                        v.visit_list n_extern_calls
                end
 
@@ -1463,7 +1514,6 @@ redef class ACallExpr
                if not n_expr isa AImplicitSelfExpr and not can_inline then
                        v.addn
                        v.addt
-                       v.addt
                end
 
                v.visit n_id
@@ -1624,8 +1674,9 @@ redef class ANewExpr
 
                        if not can_inline then
                                v.addn
+                               v.indent += 1
                                v.addt
-                               v.addt
+                               v.indent -= 1
                        end
 
                        v.visit n_id
@@ -1733,16 +1784,15 @@ redef class AAssertExpr
                                v.visit n_else
                        else
                                v.addn
+                               v.indent += 1
 
                                if n_else isa ABlockExpr then
-                                       v.indent += 1
                                        n_else.force_block = true
                                        v.visit n_else
                                        v.indent -= 1
                                        v.addt
                                        v.visit n_else.n_kwend
                                else
-                                       v.indent += 1
                                        v.addt
                                        v.visit n_else
                                        v.addn
@@ -1881,8 +1931,9 @@ private class ABinOpHelper
                        v.visit bin_expr2
                else
                        v.addn
+                       v.indent += 1
                        v.addt
-                       v.addt
+                       v.indent -= 1
                        v.visit bin_expr2
                end
        end
@@ -2028,7 +2079,7 @@ end
 redef class AArrayExpr
        redef fun accept_pretty_printer(v) do
                v.consume "["
-               v.visit_list n_exprs.n_exprs
+               v.visit_list n_exprs
                v.consume "]"
        end
 end
@@ -2057,9 +2108,13 @@ end
 
 redef class AStringFormExpr
        redef fun accept_pretty_printer(v) do
-               var can_inline = v.can_inline(self)
-
-               if can_inline then
+               if not v.break_strings then
+                       # n_string.force_inline = true
+                       v.visit n_string
+                       return
+               end
+               if v.can_inline(self) then
+                       n_string.force_inline = true
                        v.visit n_string
                else
                        var text = n_string.text
@@ -2087,7 +2142,12 @@ end
 
 redef class ASuperstringExpr
        redef fun accept_pretty_printer(v) do
-               for n_expr in n_exprs do v.visit n_expr
+               for n_expr in n_exprs do
+                       if not v.break_strings then
+                               n_expr.force_inline = true
+                       end
+                       v.visit n_expr
+               end
        end
 
        redef fun must_be_inline do