1 # This file is part of NIT ( http://www.nitlanguage.org ).
3 # Licensed under the Apache License, Version 2.0 (the "License");
4 # you may not use this file except in compliance with the License.
5 # You may obtain a copy of the License at
7 # http://www.apache.org/licenses/LICENSE-2.0
9 # Unless required by applicable law or agreed to in writing, software
10 # distributed under the License is distributed on an "AS IS" BASIS,
11 # WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
12 # See the License for the specific language governing permissions and
13 # limitations under the License.
15 # Library used to pretty print Nit code.
20 # var tc = new ToolContext
21 # var nmodule = tc.parse_something("class A\nfun toto : Int do return 5\nend")
22 # var ppv = new PrettyPrinterVisitor
23 # var pmodule = ppv.pretty(nmodule)
24 # assert pmodule.write_to_string == """
26 # \tfun toto: Int do return 5
29 # See `nitpretty` tool for more documentation.
37 # The `PrettyPrinterVisitor` is used to visit a node and pretty print it.
39 # The main method here is `visit` that performs the pretty printing of a `ANode`.
41 # Because some tokens like `TComment` are not stored in the AST,
42 # we visit the AST like traditionnal visitor and also maintain a
43 # pointer to the `current_token` (actually the next one to be printed).
45 # Visited productions are in charges to move the token pointer using methods such as:
47 # * `consume`: print `current_token` and move to the next one
48 # * `skip`: move to the next token without printing the current one
49 # * `skip_to`: move to a specified token skipping all the tokens before
50 # * `catch_up`: consume all the tokens between `current_token` and a specified token
51 # * `finish_line`: consume all the tokens between `current_token` and the end of line
52 class PrettyPrinterVisitor
54 fun pretty
(n
: ANode): Template do
59 current_token
= n
.first_token
61 else if n
isa Token then
64 while p
!= null and not p
isa Prod do
68 current_token
= p
.first_token
72 return tpl
.as(not null)
75 # Pretty print the whole `nmodule` with comments before and after.
76 fun pretty_nmodule
(nmodule
: AModule): Template do
78 nmodule
.parentize_tokens
79 current_token
= nmodule
.location
.file
.first_token
81 catch_up nmodule
.location
.file
.last_token
82 if skip_empty
then tpl
.add
"\n"
83 return tpl
.as(not null)
86 # Prepare `self` for a new visit.
96 # Visit `n` if not null.
97 fun visit
(n
: nullable ANode) do
98 if n
== null then return
99 n
.accept_pretty_printer
self
102 # Visit a list of `Anode`.
103 fun visit_list
(n
: nullable ANodes[ANode]) do
104 if n
== null then return
105 n
.accept_pretty_printer
self
108 # Is the node inlinable and can fit on the line.
109 fun can_inline
(n
: nullable ANode): Bool do
110 if n
== null then return true
111 if n
.must_be_inline
then return true
112 if n
.must_be_block
then return false
114 if n
.collect_length
+ current_length
> max_size
then return false
115 # check block is inlinable
116 return n
.is_inlinable
119 # Collect all `TComment` between `from` and `to`.
120 fun collect_comments
(from
: nullable ANode, to
: nullable ANode): Array[TComment] do
121 var res
= new Array[TComment]
122 if from
isa Prod then from
= from
.first_token
123 if to
isa Prod then to
= to
.first_token
124 if from
== null or to
== null then return res
127 if from
isa TComment then res
.add from
128 from
= from
.as(Token).next_token
134 # Token under cursor.
136 # This is the next token to visit.
137 var current_token
: nullable Token = null
139 # Skip the `current_token`.
140 fun skip
do current_token
= current_token
.next_token
142 # Skip `current_token` until the end of line.
143 fun skip_line
do current_token
= current_token
.last_real_token_in_line
145 # Skip `current_token` until `target` is reached.
146 fun skip_to
(target
: nullable Token) do
147 if target
== null then return
148 while current_token
!= null and current_token
!= target
do skip
149 if current_token
== null then
150 target
.debug
("Looked for, but not found :(")
155 # Visit `current_token`.
156 fun consume
(token
: String) do
157 if current_token
.text
== token
then else current_token
.debug
("Got `{current_token.text}`; expected `{token}`.")
161 # Is there token to visit between `current_token` and `target`?
162 fun need_catch_up
(target
: nullable Token): Bool do
163 if target
== null then return false
164 return current_token
!= target
167 # Visit all tokens between `current_token` and `target`.
168 fun catch_up
(target
: nullable ANode) do
169 if target
== null then return
170 if current_token
== null then return
172 if target
isa Token then
174 else if target
isa Prod then
175 token
= target
.first_token
.as(not null)
179 if current_token
.location
> token
.location
then return
180 while current_token
!= token
do visit current_token
183 # Visit all tokens between `current_token` and the end of line.
185 if current_token
isa TComment then
190 while current_token
isa TEol do visit
(current_token
)
193 # The template under construction.
194 private var tpl
: nullable Template = null
196 # Current indent level.
199 # Size of a tabulation in spaces.
205 # Length of the current line.
206 var current_length
= 0
208 # Length of the previous line.
209 var previous_length
= 0
211 # Is the last line a blank line?
212 fun last_line_is_blank
: Bool do return previous_length
== 0
214 # Add `t` to current template.
215 fun add
(t
: String) do
216 if t
.is_empty
then return
217 while wait_addn
> 0 do
222 current_length
+= t
.length
227 if current_length
== 0 and last_line_is_blank
then return
228 previous_length
= current_length
230 if skip_empty
then wait_addn
+= 1
233 # Perform `addn` even if not `skip_empty`.
235 if current_length
== 0 and last_line_is_blank
then return
236 previous_length
= current_length
241 # End of line chars are stored until another char is added.
242 # This avoid empty files with only a '`\n`'.
243 private var wait_addn
= 0
245 # Add `'\t' * indent`.
246 fun addt
do add
"\t" * indent
251 # Visit explicit receiver, implicit self will be ignored.
252 fun visit_recv
(n_expr
: AExpr) do
253 if not n_expr
isa AImplicitSelfExpr then
259 # Do we break string literals that are too long?
260 var break_strings
= false is public
writable
262 # Do we force `do` to be on the same line as the method signature?
263 var inline_do
= false is public
writable
265 # Do we force the deletion of empty lines?
266 var skip_empty
= false is public
writable
269 # Base framework redefs
271 redef class ANodes[E
]
272 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) do
274 var e_can_inline
= v
.can_inline
(e
)
277 if not e_can_inline
then
294 # Start visit of `self` using a `PrettyPrinterVisitor`
295 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) is abstract
297 # Collect the length (in `Char`) of the node.
298 private fun collect_length
: Int is abstract
300 # Is `self` printable in one line?
301 private fun is_inlinable
: Bool do return true
303 # Force `self` to be rendered as a block.
304 private var force_block
= false
306 # Does `self` have to be rendered as a block?
307 private fun must_be_block
: Bool do return force_block
309 # Force `self` to be rendered as a line.
310 private var force_inline
= false
312 # Does `self` have be rendered as a line?
313 private fun must_be_inline
: Bool do
314 if parent
!= null and parent
.must_be_inline
then return true
318 # Does `self` was written in one line before transformation?
319 private fun was_inline
: Bool is abstract
323 redef fun accept_pretty_printer
(v
) do
325 v
.current_token
= next_token
328 redef fun collect_length
do return text
.length
329 redef fun is_inlinable
do return true
330 redef fun was_inline
do return true
334 redef fun accept_pretty_printer
(v
) do
339 v
.current_token
= next_token
345 redef fun accept_pretty_printer
(v
) do v
.visit first_token
347 # The token where the production really start (skipping ADoc).
348 private fun start_token
: nullable Token do return first_token
350 # Collect all `TComment` contained in the production
351 # (between `start_token` and `end_token`).
352 private fun collect_comments
: Array[TComment] do
353 var res
= new Array[TComment]
354 if start_token
== null or last_token
== null then return res
355 var token
= start_token
357 while token
!= last_token
do
358 if token
isa TComment then res
.add token
359 token
= token
.next_token
365 redef fun collect_length
do
367 if start_token
== null or last_token
== null then return res
368 var token
= start_token
370 while token
!= last_token
do
371 res
+= token
.text
.length
372 token
= token
.next_token
375 res
+= token
.text
.length
379 redef fun was_inline
do
380 return start_token
.location
.line_start
== last_token
.location
.line_end
387 redef fun accept_pretty_printer
(v
) do
398 if is_last_in_group
then v
.addn
412 if next_token
isa TComment and is_first_in_group
then v
.addn
416 var prev_token
= self.prev_token
417 if prev_token
isa TComment and prev_token
.is_inline
and is_last_in_group
then v
.addn
422 if not v
.skip_empty
then v
.forcen
425 # Is `self` part of an `ADoc`?
426 private fun is_adoc
: Bool do return parent
isa ADoc and parent
.parent
!= null
428 # Is `self` part of a licence?
429 private fun is_licence
: Bool do
430 var prev_token
= self.prev_token
432 if prev_token
== null then
434 else if prev_token
isa TComment then
435 return prev_token
.is_licence
441 # Is `self` starts and ends its line?
442 private fun is_inline
: Bool do
443 return self == first_real_token_in_line
and self == last_real_token_in_line
446 # Is `self` an orphan line (blank before and after)?
447 private fun is_orphan
: Bool do
448 return prev_token
isa TEol and
449 (prev_token
.prev_token
isa TEol or prev_token
.prev_token
isa TComment) and
453 # Is `self` the first comment of a group of comment?
454 private fun is_first_in_group
: Bool do return not prev_token
isa TComment
456 # Is `self` the last comment of a group of comments?
457 private fun is_last_in_group
: Bool do return not next_token
isa TComment
461 redef fun accept_pretty_printer
(v
) do for comment
in n_comment
do v
.visit comment
462 redef fun is_inlinable
do return n_comment
.length
<= 1
467 redef class AAnnotations
468 redef fun accept_pretty_printer
(v
) do
471 if v
.can_inline
(self) then
473 for n_item
in n_items
do
475 if n_item
!= n_items
.last
then
479 if not was_inline
then
481 if v
.current_token
isa TKwend then v
.skip
486 for n_item
in n_items
do
490 if n_item
!= n_items
.last
then
502 redef fun is_inlinable
do
503 if not super then return false
504 for annot
in n_items
do if not annot
.is_inlinable
then return false
509 redef class AAnnotation
510 redef fun accept_pretty_printer
(v
) do
511 if n_visibility
!= null and not n_visibility
isa APublicVisibility then
516 if not n_args
.is_empty
then
517 if n_opar
== null then
528 redef class ATypeExpr
529 redef fun accept_pretty_printer
(v
) do v
.visit n_type
535 redef fun accept_pretty_printer
(v
) do
536 v
.catch_up start_token
539 if not n_imports
.is_empty
then
540 if v
.skip_empty
then v
.addn
542 for n_import
in n_imports
do
548 if not n_extern_code_blocks
.is_empty
then
551 for n_extern_block
in n_extern_code_blocks
do
552 v
.catch_up n_extern_block
553 v
.visit n_extern_block
555 if n_extern_block
!= n_extern_code_blocks
.last
then v
.addn
558 if not n_classdefs
.is_empty
then v
.addn
561 if not n_classdefs
.is_empty
then
562 if v
.skip_empty
then v
.addn
564 for n_classdef
in n_classdefs
do
565 v
.catch_up n_classdef
567 if n_classdef
!= n_classdefs
.last
then v
.addn
575 redef fun start_token
do
576 if n_moduledecl
!= null then return n_moduledecl
.first_token
577 if not n_imports
.is_empty
then return n_imports
.first
.first_token
578 if not n_classdefs
.is_empty
then return n_classdefs
.first
.first_token
582 redef fun is_inlinable
do return false
585 redef class AModuledecl
586 redef fun accept_pretty_printer
(v
) do
592 if n_annotations
!= null then
593 var annot_inline
= v
.can_inline
(n_annotations
)
594 v
.visit n_annotations
596 if not annot_inline
then
597 if v
.current_token
isa TKwend then
607 if v
.skip_empty
then v
.addn
611 redef class AModuleName
612 redef fun accept_pretty_printer
(v
) do
613 for path
in n_path
do
622 redef class ANoImport
623 redef fun accept_pretty_printer
(v
) do
628 if v
.skip_empty
then v
.addn
632 redef class AStdImport
633 redef fun accept_pretty_printer
(v
) do
634 if not n_visibility
isa APublicVisibility then
643 if v
.skip_empty
then v
.addn
649 redef class AClassdef
650 redef fun accept_pretty_printer
(v
) do
651 for n_propdef
in n_propdefs
do
654 if n_propdef
.n_doc
!= null or not v
.can_inline
(n_propdef
) then
655 if v
.skip_empty
and n_propdef
!= n_propdefs
.first
then v
.addn
657 if v
.skip_empty
and n_propdef
!= n_propdefs
.last
then v
.addn
665 redef class AStdClassdef
666 redef fun accept_pretty_printer
(v
) do
668 var can_inline
= v
.can_inline
(self)
670 if not n_visibility
isa APublicVisibility then
675 if n_kwredef
!= null then
684 if not n_formaldefs
.is_empty
then
686 v
.visit_list n_formaldefs
690 if n_extern_code_block
!= null then
692 v
.visit n_extern_code_block
698 if not n_propdefs
.is_empty
then
699 for n_superclass
in n_propdefs
do
706 if v
.skip_empty
then v
.addn
716 if v
.skip_empty
then v
.addn
720 redef fun is_inlinable
do
721 if not super then return false
722 # FIXME: repair pretty-printing one-liner classes
723 if n_propdefs
.length
> 0 then return false
724 #if n_propdefs.length == 1 and not n_propdefs.first isa ASuperPropdef then return false
725 if not collect_comments
.is_empty
then return false
729 redef fun start_token
do
730 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
731 if n_kwredef
!= null then return n_kwredef
732 return n_classkind
.first_token
736 redef class AAbstractClasskind
737 redef fun accept_pretty_printer
(v
) do
744 redef class AExternClasskind
745 redef fun accept_pretty_printer
(v
) do
752 redef class AFormaldef
753 redef fun accept_pretty_printer
(v
) do
756 if n_type
!= null then
765 redef fun accept_pretty_printer
(v
) do
766 if n_kwnullable
!= null then
773 if not n_types
.is_empty
then
784 redef fun accept_pretty_printer
(v
) do
788 if not n_visibility
isa nullable APublicVisibility then
793 if n_kwredef
!= null then
799 # Factorize annotations visit for all APropdef.
801 # Return true if annotations were inlined.
802 fun visit_annotations
(v
: PrettyPrinterVisitor, n_annotations
: nullable AAnnotations): Bool do
803 var res
= v
.can_inline
(n_annotations
)
804 if n_annotations
!= null then v
.visit n_annotations
808 # Factorize block visit for APropdefs.
810 # Were annotations printed inline? If so, we need to print the block differently.
811 fun visit_block
(v
: PrettyPrinterVisitor, n_block
: nullable AExpr, annot_inline
: Bool) do
812 # var can_inline = v.can_inline(n_block)
813 if n_block
== null then return
814 if n_annotations
!= null and not annot_inline
then
819 while not v
.current_token
isa TKwdo do v
.skip
821 var token
= v
.current_token
824 if token
isa TEol then
826 if not v
.can_inline
(n_block
) then
832 token
= v
.current_token
833 if token
isa TKwdo then break
835 if annot_inline
and do_inline
then v
.adds
838 if v
.can_inline
(n_block
) and do_inline
then
841 if n_block
isa ABlockExpr then
842 if n_block
.n_expr
.is_empty
then
843 v
.visit n_block
.n_kwend
845 v
.visit n_block
.n_expr
.first
846 v
.current_token
= n_block
.n_kwend
851 if v
.current_token
isa TKwend then v
.skip
862 if n_block
isa ABlockExpr then
863 n_block
.force_block
= true
865 v
.catch_up n_block
.n_kwend
874 if n_block
isa ABlockExpr then
875 v
.visit n_block
.n_kwend
883 redef fun start_token
do
884 if n_doc
== null then return super
885 return n_doc
.last_token
.next_token
889 redef class AAttrPropdef
890 redef fun accept_pretty_printer
(v
) do
896 if n_type
!= null then
902 if n_expr
!= null then
909 var annot_inline
= visit_annotations
(v
, n_annotations
)
910 visit_block
(v
, n_block
, annot_inline
)
915 redef fun first_token
do
916 if n_doc
!= null then return n_doc
.first_token
917 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
918 if n_kwredef
!= null then return n_kwredef
922 redef fun is_inlinable
do return true
925 redef class ATypePropdef
926 redef fun accept_pretty_printer
(v
) do
934 visit_annotations
(v
, n_annotations
)
939 redef fun is_inlinable
do return true
942 redef class AMethPropdef
943 redef fun accept_pretty_printer
(v
) do
944 # TODO: Handle extern annotations
946 var before
= v
.indent
948 if n_kwinit
!= null then v
.visit n_kwinit
949 if n_kwmeth
!= null then v
.visit n_kwmeth
950 if n_kwnew
!= null then v
.visit n_kwnew
952 if not n_methid
== null then
959 var annot_inline
= visit_annotations
(v
, n_annotations
)
961 if n_extern_calls
!= null or n_extern_code_block
!= null then
963 if n_extern_calls
!= null then v
.visit n_extern_calls
964 if n_extern_code_block
!= null then v
.visit n_extern_code_block
967 visit_block
(v
, n_block
, annot_inline
)
969 assert v
.indent
== before
973 # * block is empty or can be inlined
974 # * contains no comments
975 redef fun is_inlinable
do
976 if not super then return false
977 if n_annotations
!= null and not n_annotations
.is_inlinable
then return false
978 if n_block
!= null and not n_block
.is_inlinable
then return false
979 if n_extern_calls
!= null and not n_extern_calls
.is_inlinable
then return false
980 if n_extern_code_block
!= null and not n_extern_code_block
.is_inlinable
then return false
981 if not collect_comments
.is_empty
then return false
986 redef class AMainMethPropdef
987 redef fun accept_pretty_printer
(v
) do
989 if v
.skip_empty
then v
.addn
993 redef class ASuperPropdef
994 redef fun accept_pretty_printer
(v
) do
999 visit_annotations
(v
, n_annotations
)
1004 redef fun is_inlinable
do return true
1007 redef class ASignature
1008 redef fun accept_pretty_printer
(v
) do
1009 if not n_params
.is_empty
then
1011 v
.visit_list n_params
1015 if n_type
!= null then
1024 redef fun accept_pretty_printer
(v
) do
1027 if n_type
!= null then
1033 if n_dotdotdot
!= null then v
.visit n_dotdotdot
1039 redef class AExternCalls
1040 redef fun accept_pretty_printer
(v
) do
1041 var can_inline
= v
.can_inline
(self)
1046 v
.visit_list n_extern_calls
1052 v
.visit_list n_extern_calls
1059 redef class AFullPropExternCall
1060 redef fun accept_pretty_printer
(v
) do
1067 redef class ALocalPropExternCall
1068 redef fun accept_pretty_printer
(v
) do v
.visit n_methid
1071 redef class AInitPropExternCall
1072 redef fun accept_pretty_printer
(v
) do v
.visit n_type
1075 redef class ACastAsExternCall
1076 redef fun accept_pretty_printer
(v
) do
1086 redef class AAsNullableExternCall
1087 redef fun accept_pretty_printer
(v
) do
1092 v
.visit n_kwnullable
1096 redef class AAsNotNullableExternCall
1097 redef fun accept_pretty_printer
(v
) do
1104 v
.visit n_kwnullable
1108 redef class AExternCodeBlock
1109 redef fun accept_pretty_printer
(v
) do
1110 if n_in_language
!= null then
1111 v
.visit n_in_language
1115 v
.visit n_extern_code_segment
1118 redef fun is_inlinable
do
1119 if not super then return false
1120 return n_extern_code_segment
.is_inlinable
1124 redef class AInLanguage
1125 redef fun accept_pretty_printer
(v
) do
1132 redef class TExternCodeSegment
1133 redef fun accept_pretty_printer
(v
) do
1134 var can_inline
= v
.can_inline
(self)
1139 var text
= text
.substring
(2, text
.length
- 4)
1140 var lines
= text
.r_trim
.split
("\n")
1142 if text
.is_empty
then
1147 if not lines
.first
.trim
.is_empty
then
1155 for line
in lines
do
1164 v
.current_token
= next_token
1168 redef fun is_inlinable
do
1169 if not super then return false
1170 return location
.line_start
== location
.line_end
1176 redef class ABlockExpr
1177 redef fun accept_pretty_printer
(v
) do
1178 var before
= v
.indent
1179 var can_inline
= v
.can_inline
(self)
1181 if can_inline
and not n_expr
.is_empty
then
1182 v
.visit n_expr
.first
1185 for nexpr
in n_expr
do
1186 var expr_inline
= v
.can_inline
(nexpr
)
1187 if not expr_inline
and nexpr
!= n_expr
.first
then v
.addn
1193 if not expr_inline
and nexpr
!= n_expr
.last
then v
.addn
1197 assert v
.indent
== before
1200 redef fun is_inlinable
do
1201 if not super then return false
1202 if not collect_comments
.is_empty
then return false
1204 if not n_expr
.is_empty
then
1205 if n_expr
.length
> 1 then return false
1206 if not n_expr
.first
.is_inlinable
then return false
1214 redef fun accept_pretty_printer
(v
) do
1215 var before
= v
.indent
1216 var can_inline
= v
.can_inline
(self)
1220 if v
.can_inline
(n_expr
) then
1229 # skip comments before `then` token
1230 while not v
.current_token
isa TKwthen do v
.skip
1232 var n_else
= self.n_else
1236 if n_then
!= null then v
.visit n_then
1239 n_else
.force_inline
= true
1244 else if n_then
== null then
1247 v
.skip_to last_token
.last_real_token_in_line
1252 else if not v
.skip_empty
and n_then
!= null and
1253 n_then
.was_inline
and
1254 n_then
.location
.line_end
== location
.line_start
then
1255 v
.forcen
# Xymus fucking syntax
1261 if n_then
!= null then
1262 if n_then
isa ABlockExpr then
1263 n_then
.force_block
= true
1268 if n_then
.was_inline
then
1277 while not v
.current_token
isa TKwelse do
1278 v
.consume v
.current_token
.text
1285 if n_else
isa AIfExpr then
1286 n_else
.force_block
= true
1298 if n_else
isa ABlockExpr then
1299 n_else
.force_block
= true
1304 if n_else
.was_inline
then
1311 if last_token
isa TKwend then
1312 v
.catch_up last_token
1323 if last_token
.location
>= v
.current_token
.location
then v
.catch_up last_token
1327 if v
.current_token
isa TKwend then v
.skip
1331 assert v
.indent
== before
1334 redef fun is_inlinable
do
1335 if not super then return false
1336 if n_then
!= null and not n_then
.is_inlinable
then return false
1337 var n_else
= self.n_else
1338 if (n_else
isa ABlockExpr and not n_else
.n_expr
.is_empty
) or
1339 (not n_else
isa ABlockExpr and n_else
!= null) then
1342 if not collect_comments
.is_empty
then return false
1346 # Does this `if` statement contains a `else` part?
1347 private fun has_else
(v
: PrettyPrinterVisitor): Bool do
1349 if n_else
== null then return false
1350 var n_kwelse
= collect_kwelse
1351 if n_kwelse
== null then return false
1353 if n_else
isa ABlockExpr then
1354 var comments
: Array[TComment]
1356 if n_then
== null then
1357 comments
= v
.collect_comments
(n_expr
.last_token
, n_else
.last_token
)
1359 comments
= v
.collect_comments
(n_then
.last_token
, n_else
.last_token
)
1362 if not comments
.is_empty
then return true
1363 return not n_else
.n_expr
.is_empty
1369 # Lookup for `else` token in `self`.
1370 private fun collect_kwelse
: nullable TKwelse do
1371 var token
= first_token
1373 while token
!= last_token
do
1374 if token
isa TKwelse then return token
1375 token
= token
.next_token
1382 # Used to factorize work on loops.
1383 private class ALoopHelper
1386 fun loop_block
: nullable ANode is abstract
1387 fun loop_label
: nullable ANode is abstract
1389 fun visit_loop_block
(v
: PrettyPrinterVisitor) do
1390 var n_block
= loop_block
1395 if n_block
isa ABlockExpr then
1396 n_block
.force_block
= true
1398 v
.catch_up n_block
.n_kwend
1401 v
.visit n_block
.n_kwend
1411 if loop_label
!= null then
1417 fun visit_loop_inline
(v
: PrettyPrinterVisitor) do
1418 var n_block
= loop_block
1421 if n_block
isa ABlockExpr then
1422 if n_block
.n_expr
.is_empty
then
1423 v
.visit n_block
.n_kwend
1425 v
.visit n_block
.n_expr
.first
1426 v
.current_token
= n_block
.n_kwend
1431 if v
.current_token
isa TKwend then v
.skip
1434 if loop_label
!= null then
1440 redef fun is_inlinable
do
1441 var n_block
= loop_block
1442 if not super then return false
1443 if n_block
isa ABlockExpr and not n_block
.is_inlinable
then return false
1444 if not collect_comments
.is_empty
then return false
1449 redef class ALoopExpr
1452 redef fun loop_block
do return n_block
1453 redef fun loop_label
do return n_label
1455 redef fun accept_pretty_printer
(v
) do
1456 var can_inline
= v
.can_inline
(self)
1458 if can_inline
then visit_loop_inline v
else visit_loop_block v
1462 redef class AWhileExpr
1465 redef fun loop_block
do return n_block
1466 redef fun loop_label
do return n_label
1468 redef fun accept_pretty_printer
(v
) do
1469 var can_inline
= v
.can_inline
(self)
1475 if can_inline
then visit_loop_inline v
else visit_loop_block v
1482 redef fun loop_block
do return n_block
1483 redef fun loop_label
do return n_label
1485 redef fun accept_pretty_printer
(v
) do
1486 var can_inline
= v
.can_inline
(self)
1488 if can_inline
then visit_loop_inline v
else visit_loop_block v
1492 redef class AForExpr
1495 redef fun loop_block
do return n_block
1496 redef fun loop_label
do return n_label
1498 redef fun accept_pretty_printer
(v
) do
1499 var can_inline
= v
.can_inline
(self)
1503 for n_id
in n_ids
do
1505 if n_id
!= n_ids
.last
then v
.add
", "
1514 if can_inline
then visit_loop_inline v
else visit_loop_block v
1518 redef class ABreakExpr
1519 redef fun accept_pretty_printer
(v
) do
1522 if n_expr
!= null then
1527 if n_label
!= null then
1533 redef fun is_inlinable
do return true
1536 redef class AContinueExpr
1537 redef fun accept_pretty_printer
(v
) do
1538 v
.visit n_kwcontinue
1540 if n_expr
!= null then
1545 if n_label
!= null then
1551 redef fun is_inlinable
do return true
1556 redef class ASendExpr
1557 redef fun is_inlinable
do return true
1560 redef class ACallExpr
1561 redef fun accept_pretty_printer
(v
) do
1562 var can_inline
= v
.can_inline
(self)
1565 if not n_expr
isa AImplicitSelfExpr and not can_inline
then
1572 if not n_args
.n_exprs
.is_empty
then
1573 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1575 if v
.current_token
isa TOpar then v
.skip
1576 v
.visit n_args
.n_exprs
.first
1577 if v
.current_token
isa TCpar then v
.skip
1579 if v
.current_token
isa TOpar then
1585 v
.visit_list n_args
.n_exprs
1586 if v
.current_token
isa TCpar then v
.consume
")"
1591 # Is the call alone on its line?
1592 fun is_stmt
: Bool do return parent
isa ABlockExpr
1595 redef class ACallAssignExpr
1596 redef fun accept_pretty_printer
(v
) do
1600 if not n_args
.n_exprs
.is_empty
then
1602 v
.visit_list n_args
.n_exprs
1613 redef class ACallReassignExpr
1614 redef fun accept_pretty_printer
(v
) do
1618 if not n_args
.n_exprs
.is_empty
then
1620 v
.visit_list n_args
.n_exprs
1631 redef class ABraExpr
1632 redef fun accept_pretty_printer
(v
) do
1635 if not n_args
.n_exprs
.is_empty
then
1637 v
.visit_list n_args
.n_exprs
1643 redef class ABraAssignExpr
1644 redef fun accept_pretty_printer
(v
) do
1647 if not n_args
.n_exprs
.is_empty
then
1649 v
.visit_list n_args
.n_exprs
1660 redef class ABraReassignExpr
1661 redef fun accept_pretty_printer
(v
) do
1664 if not n_args
.n_exprs
.is_empty
then
1666 v
.visit_list n_args
.n_exprs
1677 redef class AAssignMethid
1678 redef fun accept_pretty_printer
(v
) do
1684 redef class ABraMethid
1685 redef fun accept_pretty_printer
(v
) do
1691 redef class ABraassignMethid
1692 redef fun accept_pretty_printer
(v
) do
1699 redef class AInitExpr
1700 redef fun accept_pretty_printer
(v
) do
1701 if not n_expr
isa AImplicitSelfExpr then
1708 if not n_args
.n_exprs
.is_empty
then
1710 v
.visit_list n_args
.n_exprs
1716 redef class ANewExpr
1717 redef fun accept_pretty_printer
(v
) do
1718 var can_inline
= v
.can_inline
(self)
1723 if n_id
!= null then
1726 if not can_inline
then
1736 if not n_args
.n_exprs
.is_empty
then
1738 v
.visit_list n_args
.n_exprs
1743 redef fun is_inlinable
do return true
1748 redef class AAttrExpr
1749 redef fun accept_pretty_printer
(v
) do
1754 redef fun is_inlinable
do return true
1757 redef class AAttrAssignExpr
1758 redef fun accept_pretty_printer
(v
) do
1768 redef class AAttrReassignExpr
1769 redef fun accept_pretty_printer
(v
) do
1781 redef class AVardeclExpr
1782 redef fun accept_pretty_printer
(v
) do
1787 if n_type
!= null then
1793 if n_expr
!= null then
1801 redef fun is_inlinable
do return true
1804 redef class AVarAssignExpr
1805 redef fun accept_pretty_printer
(v
) do
1814 redef class AAssertExpr
1815 redef fun accept_pretty_printer
(v
) do
1816 var can_inline
= v
.can_inline
(self)
1819 if n_id
!= null then
1827 var n_else
= self.n_else
1829 if n_else
!= null then
1840 if n_else
isa ABlockExpr then
1841 n_else
.force_block
= true
1845 v
.visit n_else
.n_kwend
1858 redef fun is_inlinable
do
1859 if not super then return false
1860 if n_else
!= null and not n_else
.is_inlinable
then return false
1865 redef class AReturnExpr
1866 redef fun accept_pretty_printer
(v
) do
1869 if n_expr
!= null then
1876 redef class ASuperExpr
1877 redef fun accept_pretty_printer
(v
) do
1880 if not n_args
.n_exprs
.is_empty
then
1881 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1883 if v
.current_token
isa TOpar then v
.skip
1884 v
.visit n_args
.n_exprs
.first
1885 if v
.current_token
isa TCpar then v
.skip
1887 if v
.current_token
isa TOpar then
1893 v
.visit_list n_args
.n_exprs
1894 if v
.current_token
isa TCpar then v
.consume
")"
1899 # Is the call alone on its line?
1900 fun is_stmt
: Bool do return self.first_token
.is_starting_line
1902 redef fun is_inlinable
do return true
1905 redef class AOnceExpr
1906 redef fun accept_pretty_printer
(v
) do
1912 redef fun is_inlinable
do return true
1915 redef class AAbortExpr
1916 redef fun accept_pretty_printer
(v
) do v
.visit n_kwabort
1917 redef fun is_inlinable
do return true
1920 redef class ANotExpr
1921 redef fun accept_pretty_printer
(v
) do
1928 redef class AAsCastExpr
1929 redef fun accept_pretty_printer
(v
) do
1939 redef class AAsNotnullExpr
1940 redef fun accept_pretty_printer
(v
) do
1954 # Used to factorize work on Or, And, Implies and Binop expressions.
1955 private class ABinOpHelper
1958 fun bin_expr1
: AExpr is abstract
1959 fun bin_expr2
: AExpr is abstract
1962 fun bin_op
: String is abstract
1964 redef fun accept_pretty_printer
(v
) do
1965 var can_inline
= v
.can_inline
(self)
1967 if not can_inline
then
1968 if (self isa ABinopExpr and bin_expr1
isa ABinopExpr) or
1969 (self isa AAndExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr)) or
1970 (self isa AOrExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr))
1972 bin_expr1
.force_block
= true
1993 redef class AAndExpr
1996 redef fun bin_expr1
do return n_expr
1997 redef fun bin_expr2
do return n_expr2
1998 redef fun bin_op
do return "and"
2004 redef fun bin_expr1
do return n_expr
2005 redef fun bin_expr2
do return n_expr2
2006 redef fun bin_op
do return "or"
2009 redef class AImpliesExpr
2012 redef fun bin_expr1
do return n_expr
2013 redef fun bin_expr2
do return n_expr2
2014 redef fun bin_op
do return "implies"
2017 redef class ABinopExpr
2020 redef fun bin_expr1
do return n_expr
2021 redef fun bin_expr2
do return n_expr2
2022 redef fun bin_op
do return operator
2025 redef class AIsaExpr
2026 redef fun accept_pretty_printer
(v
) do
2035 redef class AOrElseExpr
2036 redef fun accept_pretty_printer
(v
) do
2046 redef fun is_inlinable
do return true
2051 redef class AUplusExpr
2052 redef fun accept_pretty_printer
(v
) do
2058 redef class AUminusExpr
2059 redef fun accept_pretty_printer
(v
) do
2065 redef class ANullExpr
2066 redef fun accept_pretty_printer
(v
) do v
.visit n_kwnull
2067 redef fun is_inlinable
do return true
2070 redef class AParExpr
2071 redef fun accept_pretty_printer
(v
) do
2078 redef class AArrayExpr
2079 redef fun accept_pretty_printer
(v
) do
2081 v
.visit_list n_exprs
2086 redef class ACrangeExpr
2087 redef fun accept_pretty_printer
(v
) do
2096 redef class AOrangeExpr
2097 redef fun accept_pretty_printer
(v
) do
2108 redef class AStringFormExpr
2109 redef fun accept_pretty_printer
(v
) do
2110 if not v
.break_strings
then
2111 # n_string.force_inline = true
2115 if v
.can_inline
(self) then
2116 n_string
.force_inline
= true
2119 var text
= n_string
.text
2122 while i
< text
.length
do
2125 if v
.current_length
>= v
.max_size
and i
<= text
.length
- 3 then
2141 v
.current_token
= n_string
.next_token
2146 redef class ASuperstringExpr
2147 redef fun accept_pretty_printer
(v
) do
2148 for n_expr
in n_exprs
do
2149 if not v
.break_strings
then
2150 n_expr
.force_inline
= true
2156 redef fun must_be_inline
do
2157 if super then return true
2159 if not n_exprs
.is_empty
then
2160 var first
= n_exprs
.first
2161 return first
isa AStringFormExpr and first
.n_string
.text
.has_prefix
("\"\
"\"")