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 arguments `ANode` with optional parentheses
103 fun visit_args
(n
: nullable ANodes[ANode]) do
104 if n
== null or n
.is_empty
then return
105 if current_token
isa TOpar then
112 if current_token
isa TCpar then consume
")"
115 # Visit a list of `ANode`.
116 fun visit_list
(n
: nullable ANodes[ANode]) do
117 if n
== null then return
118 n
.accept_pretty_printer
self
121 # Is the node inlinable and can fit on the line.
122 fun can_inline
(n
: nullable ANode): Bool do
123 if n
== null then return true
124 if n
.must_be_inline
then return true
125 if n
.must_be_block
then return false
127 if n
.collect_length
+ current_length
> max_size
then return false
128 # check block is inlinable
129 return n
.is_inlinable
132 # Collect all `TComment` between `from` and `to`.
133 fun collect_comments
(from
: nullable ANode, to
: nullable ANode): Array[TComment] do
134 var res
= new Array[TComment]
135 if from
isa Prod then from
= from
.first_token
136 if to
isa Prod then to
= to
.first_token
137 if from
== null or to
== null then return res
140 if from
isa TComment then res
.add from
141 from
= from
.as(Token).next_token
147 # Token under cursor.
149 # This is the next token to visit.
150 var current_token
: nullable Token = null
152 # Skip the `current_token`.
153 fun skip
do current_token
= current_token
.next_token
155 # Skip `current_token` until the end of line.
156 fun skip_line
do current_token
= current_token
.last_real_token_in_line
158 # Skip `current_token` until `target` is reached.
159 fun skip_to
(target
: nullable Token) do
160 if target
== null then return
161 while current_token
!= null and current_token
!= target
do skip
162 if current_token
== null then
163 target
.debug
("Looked for, but not found :(")
168 # Consume comments and end of lines if any
169 fun consume_comments
do
170 while current_token
isa TEol or current_token
isa TComment do visit current_token
173 # Visit `current_token`.
174 fun consume
(token
: String) do
176 if current_token
.text
== token
then else current_token
.debug
("Got `{current_token.text}`; expected `{token}`.")
180 # Is there token to visit between `current_token` and `target`?
181 fun need_catch_up
(target
: nullable Token): Bool do
182 if target
== null then return false
183 return current_token
!= target
186 # Visit all tokens between `current_token` and `target`.
187 fun catch_up
(target
: nullable ANode) do
188 if target
== null then return
189 if current_token
== null then return
191 if target
isa Token then
193 else if target
isa Prod then
194 token
= target
.first_token
.as(not null)
198 if current_token
.location
> token
.location
then return
199 while current_token
!= token
do visit current_token
202 # Visit all tokens between `current_token` and the end of line.
204 if current_token
isa TComment then
209 while current_token
isa TEol do visit
(current_token
)
212 # The template under construction.
213 private var tpl
: nullable Template = null
215 # Current indent level.
218 # Size of a tabulation in spaces.
224 # Length of the current line.
225 var current_length
= 0
227 # Length of the previous line.
228 var previous_length
= 0
230 # Is the last line a blank line?
231 fun last_line_is_blank
: Bool do return previous_length
== 0
233 # Add `t` to current template.
234 fun add
(t
: String) do
235 if t
.is_empty
then return
236 while wait_addn
> 0 do
241 current_length
+= t
.length
246 if current_length
== 0 and last_line_is_blank
then return
247 previous_length
= current_length
249 if skip_empty
then wait_addn
+= 1
252 # Perform `addn` even if not `skip_empty`.
254 if current_length
== 0 and last_line_is_blank
then return
255 previous_length
= current_length
260 # End of line chars are stored until another char is added.
261 # This avoid empty files with only a '`\n`'.
262 private var wait_addn
= 0
264 # Add `'\t' * indent`.
265 fun addt
do add
"\t" * indent
270 # Visit explicit receiver, implicit self will be ignored.
271 fun visit_recv
(n_expr
: AExpr) do
272 if not n_expr
isa AImplicitSelfExpr then
278 # Do we break string literals that are too long?
279 var break_strings
= false is public
writable
281 # Do we force `do` to be on the same line as the method signature?
282 var inline_do
= false is public
writable
284 # Do we force the deletion of empty lines?
285 var skip_empty
= false is public
writable
288 # Base framework redefs
290 redef class ANodes[E
]
291 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) do
293 var e_can_inline
= v
.can_inline
(e
)
296 if not e_can_inline
then
313 # Start visit of `self` using a `PrettyPrinterVisitor`
314 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) is abstract
316 # Collect the length (in `Char`) of the node.
317 private fun collect_length
: Int is abstract
319 # Is `self` printable in one line?
320 private fun is_inlinable
: Bool do return true
322 # Force `self` to be rendered as a block.
323 private var force_block
= false
325 # Does `self` have to be rendered as a block?
326 private fun must_be_block
: Bool do return force_block
328 # Force `self` to be rendered as a line.
329 private var force_inline
= false
331 # Does `self` have be rendered as a line?
332 private fun must_be_inline
: Bool do
333 if parent
!= null and parent
.must_be_inline
then return true
337 # Does `self` was written in one line before transformation?
338 private fun was_inline
: Bool is abstract
342 redef fun accept_pretty_printer
(v
) do
344 v
.current_token
= next_token
347 redef fun collect_length
do return text
.length
348 redef fun is_inlinable
do return true
349 redef fun was_inline
do return true
353 redef fun accept_pretty_printer
(v
) do
358 v
.current_token
= next_token
364 redef fun accept_pretty_printer
(v
) do v
.visit first_token
366 # The token where the production really start (skipping ADoc).
367 private fun start_token
: nullable Token do return first_token
369 # Collect all `TComment` contained in the production
370 # (between `start_token` and `end_token`).
371 private fun collect_comments
: Array[TComment] do
372 var res
= new Array[TComment]
373 if start_token
== null or last_token
== null then return res
374 var token
= start_token
376 while token
!= last_token
do
377 if token
isa TComment then res
.add token
378 token
= token
.next_token
384 redef fun collect_length
do
386 if start_token
== null or last_token
== null then return res
387 var token
= start_token
389 while token
!= last_token
do
390 res
+= token
.text
.length
391 token
= token
.next_token
394 res
+= token
.text
.length
398 redef fun was_inline
do
399 return start_token
.location
.line_start
== last_token
.location
.line_end
406 redef fun accept_pretty_printer
(v
) do
417 if is_last_in_group
then v
.addn
431 if next_token
isa TComment and is_first_in_group
then v
.addn
435 var prev_token
= self.prev_token
436 if prev_token
isa TComment and prev_token
.is_inline
and is_last_in_group
then v
.addn
441 if not v
.skip_empty
then v
.forcen
444 # Is `self` part of an `ADoc`?
445 private fun is_adoc
: Bool do return parent
isa ADoc and parent
.parent
!= null
447 # Is `self` part of a licence?
448 private fun is_licence
: Bool do
449 var prev_token
= self.prev_token
451 if prev_token
== null then
453 else if prev_token
isa TComment then
454 return prev_token
.is_licence
460 # Is `self` starts and ends its line?
461 private fun is_inline
: Bool do
462 return self == first_real_token_in_line
and self == last_real_token_in_line
465 # Is `self` an orphan line (blank before and after)?
466 private fun is_orphan
: Bool do
467 return prev_token
isa TEol and
468 (prev_token
.prev_token
isa TEol or prev_token
.prev_token
isa TComment) and
472 # Is `self` the first comment of a group of comment?
473 private fun is_first_in_group
: Bool do return not prev_token
isa TComment
475 # Is `self` the last comment of a group of comments?
476 private fun is_last_in_group
: Bool do return not next_token
isa TComment
480 redef fun accept_pretty_printer
(v
) do for comment
in n_comment
do v
.visit comment
481 redef fun is_inlinable
do return n_comment
.length
<= 1
486 redef class AAnnotations
487 redef fun accept_pretty_printer
(v
) do
490 if v
.can_inline
(self) then
492 for n_item
in n_items
do
494 if n_item
!= n_items
.last
then
498 if not was_inline
then
500 if v
.current_token
isa TKwend then v
.skip
505 for n_item
in n_items
do
509 if n_item
!= n_items
.last
then
521 redef fun is_inlinable
do
522 if not super then return false
523 for annot
in n_items
do if not annot
.is_inlinable
then return false
528 redef class AAnnotation
529 redef fun accept_pretty_printer
(v
) do
530 if n_visibility
!= null and not n_visibility
isa APublicVisibility then
539 redef class ATypeExpr
540 redef fun accept_pretty_printer
(v
) do v
.visit n_type
546 redef fun accept_pretty_printer
(v
) do
547 v
.catch_up start_token
550 if not n_imports
.is_empty
then
551 if v
.skip_empty
then v
.addn
553 for n_import
in n_imports
do
559 if not n_extern_code_blocks
.is_empty
then
562 for n_extern_block
in n_extern_code_blocks
do
563 v
.catch_up n_extern_block
564 v
.visit n_extern_block
566 if n_extern_block
!= n_extern_code_blocks
.last
then v
.addn
569 if not n_classdefs
.is_empty
then v
.addn
572 if not n_classdefs
.is_empty
then
573 if v
.skip_empty
then v
.addn
575 for n_classdef
in n_classdefs
do
576 v
.catch_up n_classdef
578 if n_classdef
!= n_classdefs
.last
then v
.addn
586 redef fun start_token
do
587 if n_moduledecl
!= null then return n_moduledecl
.first_token
588 if not n_imports
.is_empty
then return n_imports
.first
.first_token
589 if not n_classdefs
.is_empty
then return n_classdefs
.first
.first_token
593 redef fun is_inlinable
do return false
596 redef class AModuledecl
597 redef fun accept_pretty_printer
(v
) do
603 if n_annotations
!= null then
604 var annot_inline
= v
.can_inline
(n_annotations
)
605 v
.visit n_annotations
607 if not annot_inline
then
608 if v
.current_token
isa TKwend then
618 if v
.skip_empty
then v
.addn
622 redef class AModuleName
623 redef fun accept_pretty_printer
(v
) do
624 for path
in n_path
do
633 redef class ANoImport
634 redef fun accept_pretty_printer
(v
) do
639 if v
.skip_empty
then v
.addn
643 redef class AStdImport
644 redef fun accept_pretty_printer
(v
) do
645 if not n_visibility
isa APublicVisibility then
654 if v
.skip_empty
then v
.addn
660 redef class AClassdef
661 redef fun accept_pretty_printer
(v
) do
662 for n_propdef
in n_propdefs
do
665 if n_propdef
.n_doc
!= null or not v
.can_inline
(n_propdef
) then
666 if v
.skip_empty
and n_propdef
!= n_propdefs
.first
then v
.addn
668 if v
.skip_empty
and n_propdef
!= n_propdefs
.last
then v
.addn
676 redef class AStdClassdef
677 redef fun accept_pretty_printer
(v
) do
679 var can_inline
= v
.can_inline
(self)
681 if not n_visibility
isa APublicVisibility then
686 if n_kwredef
!= null then
695 if not n_formaldefs
.is_empty
then
697 v
.visit_list n_formaldefs
701 if n_extern_code_block
!= null then
703 v
.visit n_extern_code_block
709 if not n_propdefs
.is_empty
then
710 for n_superclass
in n_propdefs
do
717 if v
.skip_empty
then v
.addn
727 if v
.skip_empty
then v
.addn
731 redef fun is_inlinable
do
732 if not super then return false
733 # FIXME: repair pretty-printing one-liner classes
734 if n_propdefs
.length
> 0 then return false
735 #if n_propdefs.length == 1 and not n_propdefs.first isa ASuperPropdef then return false
736 if not collect_comments
.is_empty
then return false
740 redef fun start_token
do
741 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
742 if n_kwredef
!= null then return n_kwredef
743 return n_classkind
.first_token
747 redef class AAbstractClasskind
748 redef fun accept_pretty_printer
(v
) do
755 redef class AExternClasskind
756 redef fun accept_pretty_printer
(v
) do
763 redef class AFormaldef
764 redef fun accept_pretty_printer
(v
) do
767 if n_type
!= null then
776 redef fun accept_pretty_printer
(v
) do
777 if n_kwnullable
!= null then
784 if not n_types
.is_empty
then
795 redef fun accept_pretty_printer
(v
) do
799 if not n_visibility
isa nullable APublicVisibility then
804 if n_kwredef
!= null then
810 # Factorize annotations visit for all APropdef.
812 # Return true if annotations were inlined.
813 fun visit_annotations
(v
: PrettyPrinterVisitor, n_annotations
: nullable AAnnotations): Bool do
814 var res
= v
.can_inline
(n_annotations
)
815 if n_annotations
!= null then v
.visit n_annotations
819 # Factorize block visit for APropdefs.
821 # Were annotations printed inline? If so, we need to print the block differently.
822 fun visit_block
(v
: PrettyPrinterVisitor, n_block
: nullable AExpr, annot_inline
: Bool) do
823 # var can_inline = v.can_inline(n_block)
824 if n_block
== null then return
825 if n_annotations
!= null and not annot_inline
then
830 while not v
.current_token
isa TKwdo do v
.skip
832 var token
= v
.current_token
835 if token
isa TEol then
837 if not v
.can_inline
(n_block
) then
843 token
= v
.current_token
844 if token
isa TKwdo then break
846 if annot_inline
and do_inline
then v
.adds
849 if v
.can_inline
(n_block
) and do_inline
then
852 if n_block
isa ABlockExpr then
853 if n_block
.n_expr
.is_empty
then
854 v
.visit n_block
.n_kwend
856 v
.visit n_block
.n_expr
.first
857 v
.current_token
= n_block
.n_kwend
862 if v
.current_token
isa TKwend then v
.skip
873 if n_block
isa ABlockExpr then
874 n_block
.force_block
= true
876 v
.catch_up n_block
.n_kwend
885 if n_block
isa ABlockExpr then
886 v
.visit n_block
.n_kwend
894 redef fun start_token
do
895 if n_doc
== null then return super
896 return n_doc
.last_token
.next_token
900 redef class AAttrPropdef
901 redef fun accept_pretty_printer
(v
) do
907 if n_type
!= null then
913 if n_expr
!= null then
920 var annot_inline
= visit_annotations
(v
, n_annotations
)
921 visit_block
(v
, n_block
, annot_inline
)
926 redef fun first_token
do
927 if n_doc
!= null then return n_doc
.first_token
928 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
929 if n_kwredef
!= null then return n_kwredef
933 redef fun is_inlinable
do return true
936 redef class ATypePropdef
937 redef fun accept_pretty_printer
(v
) do
945 visit_annotations
(v
, n_annotations
)
950 redef fun is_inlinable
do return true
953 redef class AMethPropdef
954 redef fun accept_pretty_printer
(v
) do
955 # TODO: Handle extern annotations
957 var before
= v
.indent
959 if n_kwinit
!= null then v
.visit n_kwinit
960 if n_kwmeth
!= null then v
.visit n_kwmeth
961 if n_kwnew
!= null then v
.visit n_kwnew
963 if not n_methid
== null then
970 var annot_inline
= visit_annotations
(v
, n_annotations
)
972 if n_extern_calls
!= null or n_extern_code_block
!= null then
974 if n_extern_calls
!= null then v
.visit n_extern_calls
975 if n_extern_code_block
!= null then v
.visit n_extern_code_block
978 visit_block
(v
, n_block
, annot_inline
)
980 assert v
.indent
== before
984 # * block is empty or can be inlined
985 # * contains no comments
986 redef fun is_inlinable
do
987 if not super then return false
988 if n_annotations
!= null and not n_annotations
.is_inlinable
then return false
989 if n_block
!= null and not n_block
.is_inlinable
then return false
990 if n_extern_calls
!= null and not n_extern_calls
.is_inlinable
then return false
991 if n_extern_code_block
!= null and not n_extern_code_block
.is_inlinable
then return false
992 if not collect_comments
.is_empty
then return false
997 redef class AMainMethPropdef
998 redef fun accept_pretty_printer
(v
) do
1000 if v
.skip_empty
then v
.addn
1004 redef class ASuperPropdef
1005 redef fun accept_pretty_printer
(v
) do
1010 visit_annotations
(v
, n_annotations
)
1015 redef fun is_inlinable
do return true
1018 redef class ASignature
1019 redef fun accept_pretty_printer
(v
) do
1020 if not n_params
.is_empty
then
1022 v
.visit_list n_params
1026 if n_type
!= null then
1035 redef fun accept_pretty_printer
(v
) do
1038 if n_type
!= null then
1044 if n_dotdotdot
!= null then v
.visit n_dotdotdot
1050 redef class AExternCalls
1051 redef fun accept_pretty_printer
(v
) do
1052 var can_inline
= v
.can_inline
(self)
1057 v
.visit_list n_extern_calls
1063 v
.visit_list n_extern_calls
1070 redef class AFullPropExternCall
1071 redef fun accept_pretty_printer
(v
) do
1078 redef class ALocalPropExternCall
1079 redef fun accept_pretty_printer
(v
) do v
.visit n_methid
1082 redef class AInitPropExternCall
1083 redef fun accept_pretty_printer
(v
) do v
.visit n_type
1086 redef class ACastAsExternCall
1087 redef fun accept_pretty_printer
(v
) do
1097 redef class AAsNullableExternCall
1098 redef fun accept_pretty_printer
(v
) do
1103 v
.visit n_kwnullable
1107 redef class AAsNotNullableExternCall
1108 redef fun accept_pretty_printer
(v
) do
1115 v
.visit n_kwnullable
1119 redef class AExternCodeBlock
1120 redef fun accept_pretty_printer
(v
) do
1121 if n_in_language
!= null then
1122 v
.visit n_in_language
1126 v
.visit n_extern_code_segment
1129 redef fun is_inlinable
do
1130 if not super then return false
1131 return n_extern_code_segment
.is_inlinable
1135 redef class AInLanguage
1136 redef fun accept_pretty_printer
(v
) do
1143 redef class TExternCodeSegment
1144 redef fun accept_pretty_printer
(v
) do
1145 var can_inline
= v
.can_inline
(self)
1150 var text
= text
.substring
(2, text
.length
- 4)
1151 var lines
= text
.r_trim
.split
("\n")
1153 if text
.is_empty
then
1158 if not lines
.first
.trim
.is_empty
then
1166 for line
in lines
do
1175 v
.current_token
= next_token
1179 redef fun is_inlinable
do
1180 if not super then return false
1181 return location
.line_start
== location
.line_end
1187 redef class ABlockExpr
1188 redef fun accept_pretty_printer
(v
) do
1189 var before
= v
.indent
1190 var can_inline
= v
.can_inline
(self)
1192 if can_inline
and not n_expr
.is_empty
then
1193 v
.visit n_expr
.first
1196 for nexpr
in n_expr
do
1197 var expr_inline
= v
.can_inline
(nexpr
)
1198 if not expr_inline
and nexpr
!= n_expr
.first
then v
.addn
1204 if not expr_inline
and nexpr
!= n_expr
.last
then v
.addn
1208 assert v
.indent
== before
1211 redef fun is_inlinable
do
1212 if not super then return false
1213 if not collect_comments
.is_empty
then return false
1215 if not n_expr
.is_empty
then
1216 if n_expr
.length
> 1 then return false
1217 if not n_expr
.first
.is_inlinable
then return false
1225 redef fun accept_pretty_printer
(v
) do
1226 var before
= v
.indent
1227 var can_inline
= v
.can_inline
(self)
1231 if v
.can_inline
(n_expr
) then
1240 # skip comments before `then` token
1241 while not v
.current_token
isa TKwthen do v
.skip
1243 var n_else
= self.n_else
1247 if n_then
!= null then v
.visit n_then
1250 n_else
.force_inline
= true
1255 else if n_then
== null then
1258 v
.skip_to last_token
.last_real_token_in_line
1263 else if not v
.skip_empty
and n_then
!= null and
1264 n_then
.was_inline
and
1265 n_then
.location
.line_end
== location
.line_start
then
1266 v
.forcen
# Xymus fucking syntax
1272 if n_then
!= null then
1273 if n_then
isa ABlockExpr then
1274 n_then
.force_block
= true
1279 if n_then
.was_inline
then
1294 if n_else
isa AIfExpr then
1295 n_else
.force_block
= true
1307 if n_else
isa ABlockExpr then
1308 n_else
.force_block
= true
1313 if n_else
.was_inline
then
1320 if last_token
isa TKwend then
1321 v
.catch_up last_token
1332 if last_token
.location
>= v
.current_token
.location
then v
.catch_up last_token
1336 if v
.current_token
isa TKwend then v
.skip
1340 assert v
.indent
== before
1343 redef fun is_inlinable
do
1344 if not super then return false
1345 if n_then
!= null and not n_then
.is_inlinable
then return false
1346 var n_else
= self.n_else
1347 if (n_else
isa ABlockExpr and not n_else
.n_expr
.is_empty
) or
1348 (not n_else
isa ABlockExpr and n_else
!= null) then
1351 if not collect_comments
.is_empty
then return false
1355 # Does this `if` statement contains a `else` part?
1356 private fun has_else
(v
: PrettyPrinterVisitor): Bool do
1358 if n_else
== null then return false
1359 var n_kwelse
= collect_kwelse
1360 if n_kwelse
== null then return false
1362 if n_else
isa ABlockExpr then
1363 var comments
: Array[TComment]
1365 if n_then
== null then
1366 comments
= v
.collect_comments
(n_expr
.last_token
, n_else
.last_token
)
1368 comments
= v
.collect_comments
(n_then
.last_token
, n_else
.last_token
)
1371 if not comments
.is_empty
then return true
1372 return not n_else
.n_expr
.is_empty
1378 # Lookup for `else` token in `self`.
1379 private fun collect_kwelse
: nullable TKwelse do
1380 var token
= first_token
1382 while token
!= last_token
do
1383 if token
isa TKwelse then return token
1384 token
= token
.next_token
1391 # Used to factorize work on loops.
1392 private class ALoopHelper
1395 fun loop_block
: nullable ANode is abstract
1396 fun loop_label
: nullable ANode is abstract
1398 fun visit_loop_block
(v
: PrettyPrinterVisitor) do
1399 var n_block
= loop_block
1404 if n_block
isa ABlockExpr then
1405 n_block
.force_block
= true
1407 v
.catch_up n_block
.n_kwend
1410 v
.visit n_block
.n_kwend
1420 if loop_label
!= null then
1426 fun visit_loop_inline
(v
: PrettyPrinterVisitor) do
1427 var n_block
= loop_block
1430 if n_block
isa ABlockExpr then
1431 if n_block
.n_expr
.is_empty
then
1432 v
.visit n_block
.n_kwend
1434 v
.visit n_block
.n_expr
.first
1435 v
.current_token
= n_block
.n_kwend
1440 if v
.current_token
isa TKwend then v
.skip
1443 if loop_label
!= null then
1449 redef fun is_inlinable
do
1450 var n_block
= loop_block
1451 if not super then return false
1452 if n_block
isa ABlockExpr and not n_block
.is_inlinable
then return false
1453 if not collect_comments
.is_empty
then return false
1458 redef class ALoopExpr
1461 redef fun loop_block
do return n_block
1462 redef fun loop_label
do return n_label
1464 redef fun accept_pretty_printer
(v
) do
1465 var can_inline
= v
.can_inline
(self)
1467 if can_inline
then visit_loop_inline v
else visit_loop_block v
1471 redef class AWhileExpr
1474 redef fun loop_block
do return n_block
1475 redef fun loop_label
do return n_label
1477 redef fun accept_pretty_printer
(v
) do
1478 var can_inline
= v
.can_inline
(self)
1484 if can_inline
then visit_loop_inline v
else visit_loop_block v
1491 redef fun loop_block
do return n_block
1492 redef fun loop_label
do return n_label
1494 redef fun accept_pretty_printer
(v
) do
1495 var can_inline
= v
.can_inline
(self)
1497 if can_inline
then visit_loop_inline v
else visit_loop_block v
1501 redef class AForExpr
1504 redef fun loop_block
do return n_block
1505 redef fun loop_label
do return n_label
1507 redef fun accept_pretty_printer
(v
) do
1508 var can_inline
= v
.can_inline
(self)
1512 for n_id
in n_ids
do
1514 if n_id
!= n_ids
.last
then v
.add
", "
1523 if can_inline
then visit_loop_inline v
else visit_loop_block v
1527 redef class ABreakExpr
1528 redef fun accept_pretty_printer
(v
) do
1531 if n_expr
!= null then
1536 if n_label
!= null then
1542 redef fun is_inlinable
do return true
1545 redef class AContinueExpr
1546 redef fun accept_pretty_printer
(v
) do
1547 v
.visit n_kwcontinue
1549 if n_expr
!= null then
1554 if n_label
!= null then
1560 redef fun is_inlinable
do return true
1565 redef class ASendExpr
1566 redef fun is_inlinable
do return true
1569 redef class ACallExpr
1570 redef fun accept_pretty_printer
(v
) do
1571 var can_inline
= v
.can_inline
(self)
1574 if not n_expr
isa AImplicitSelfExpr and not can_inline
then
1581 if not n_args
.n_exprs
.is_empty
then
1582 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1584 if v
.current_token
isa TOpar then v
.skip
1585 v
.visit n_args
.n_exprs
.first
1586 if v
.current_token
isa TCpar then v
.skip
1588 v
.visit_args n_args
.n_exprs
1593 # Is the call alone on its line?
1594 fun is_stmt
: Bool do return parent
isa ABlockExpr
1597 redef class ACallAssignExpr
1598 redef fun accept_pretty_printer
(v
) do
1602 if not n_args
.n_exprs
.is_empty
then
1604 v
.visit_list n_args
.n_exprs
1615 redef class ACallReassignExpr
1616 redef fun accept_pretty_printer
(v
) do
1620 if not n_args
.n_exprs
.is_empty
then
1622 v
.visit_list n_args
.n_exprs
1633 redef class ABraExpr
1634 redef fun accept_pretty_printer
(v
) do
1637 if not n_args
.n_exprs
.is_empty
then
1639 v
.visit_list n_args
.n_exprs
1645 redef class ABraAssignExpr
1646 redef fun accept_pretty_printer
(v
) do
1649 if not n_args
.n_exprs
.is_empty
then
1651 v
.visit_list n_args
.n_exprs
1662 redef class ABraReassignExpr
1663 redef fun accept_pretty_printer
(v
) do
1666 if not n_args
.n_exprs
.is_empty
then
1668 v
.visit_list n_args
.n_exprs
1679 redef class AAssignMethid
1680 redef fun accept_pretty_printer
(v
) do
1686 redef class ABraMethid
1687 redef fun accept_pretty_printer
(v
) do
1693 redef class ABraassignMethid
1694 redef fun accept_pretty_printer
(v
) do
1701 redef class AInitExpr
1702 redef fun accept_pretty_printer
(v
) do
1703 if not n_expr
isa AImplicitSelfExpr then
1709 v
.visit_args n_args
.n_exprs
1713 redef class ANewExpr
1714 redef fun accept_pretty_printer
(v
) do
1715 var can_inline
= v
.can_inline
(self)
1720 if n_id
!= null then
1723 if not can_inline
then
1733 v
.visit_args n_args
.n_exprs
1736 redef fun is_inlinable
do return true
1741 redef class AAttrExpr
1742 redef fun accept_pretty_printer
(v
) do
1747 redef fun is_inlinable
do return true
1750 redef class AAttrAssignExpr
1751 redef fun accept_pretty_printer
(v
) do
1761 redef class AAttrReassignExpr
1762 redef fun accept_pretty_printer
(v
) do
1774 redef class AVardeclExpr
1775 redef fun accept_pretty_printer
(v
) do
1780 if n_type
!= null then
1786 if n_expr
!= null then
1794 redef fun is_inlinable
do return true
1797 redef class AVarAssignExpr
1798 redef fun accept_pretty_printer
(v
) do
1807 redef class AAssertExpr
1808 redef fun accept_pretty_printer
(v
) do
1809 var can_inline
= v
.can_inline
(self)
1812 if n_id
!= null then
1820 var n_else
= self.n_else
1822 if n_else
!= null then
1833 if n_else
isa ABlockExpr then
1834 n_else
.force_block
= true
1838 v
.visit n_else
.n_kwend
1851 redef fun is_inlinable
do
1852 if not super then return false
1853 if n_else
!= null and not n_else
.is_inlinable
then return false
1858 redef class AReturnExpr
1859 redef fun accept_pretty_printer
(v
) do
1862 if n_expr
!= null then
1869 redef class ASuperExpr
1870 redef fun accept_pretty_printer
(v
) do
1873 if not n_args
.n_exprs
.is_empty
then
1874 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1876 if v
.current_token
isa TOpar then v
.skip
1877 v
.visit n_args
.n_exprs
.first
1878 if v
.current_token
isa TCpar then v
.skip
1880 v
.visit_args n_args
.n_exprs
1885 # Is the call alone on its line?
1886 fun is_stmt
: Bool do return self.first_token
.is_starting_line
1888 redef fun is_inlinable
do return true
1891 redef class AOnceExpr
1892 redef fun accept_pretty_printer
(v
) do
1898 redef fun is_inlinable
do return true
1901 redef class AAbortExpr
1902 redef fun accept_pretty_printer
(v
) do v
.visit n_kwabort
1903 redef fun is_inlinable
do return true
1906 redef class ANotExpr
1907 redef fun accept_pretty_printer
(v
) do
1914 redef class AAsCastExpr
1915 redef fun accept_pretty_printer
(v
) do
1925 redef class AAsNotnullExpr
1926 redef fun accept_pretty_printer
(v
) do
1940 # Used to factorize work on Or, And, Implies and Binop expressions.
1941 private class ABinOpHelper
1944 fun bin_expr1
: AExpr is abstract
1945 fun bin_expr2
: AExpr is abstract
1948 fun bin_op
: String is abstract
1950 redef fun accept_pretty_printer
(v
) do
1951 var can_inline
= v
.can_inline
(self)
1953 if not can_inline
then
1954 if (self isa ABinopExpr and bin_expr1
isa ABinopExpr) or
1955 (self isa AAndExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr)) or
1956 (self isa AOrExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr))
1958 bin_expr1
.force_block
= true
1979 redef class AAndExpr
1982 redef fun bin_expr1
do return n_expr
1983 redef fun bin_expr2
do return n_expr2
1984 redef fun bin_op
do return "and"
1990 redef fun bin_expr1
do return n_expr
1991 redef fun bin_expr2
do return n_expr2
1992 redef fun bin_op
do return "or"
1995 redef class AImpliesExpr
1998 redef fun bin_expr1
do return n_expr
1999 redef fun bin_expr2
do return n_expr2
2000 redef fun bin_op
do return "implies"
2003 redef class ABinopExpr
2006 redef fun bin_expr1
do return n_expr
2007 redef fun bin_expr2
do return n_expr2
2008 redef fun bin_op
do return operator
2011 redef class AIsaExpr
2012 redef fun accept_pretty_printer
(v
) do
2021 redef class AOrElseExpr
2022 redef fun accept_pretty_printer
(v
) do
2032 redef fun is_inlinable
do return true
2037 redef class AUplusExpr
2038 redef fun accept_pretty_printer
(v
) do
2044 redef class AUminusExpr
2045 redef fun accept_pretty_printer
(v
) do
2051 redef class ANullExpr
2052 redef fun accept_pretty_printer
(v
) do v
.visit n_kwnull
2053 redef fun is_inlinable
do return true
2056 redef class AParExpr
2057 redef fun accept_pretty_printer
(v
) do
2064 redef class AArrayExpr
2065 redef fun accept_pretty_printer
(v
) do
2067 v
.visit_list n_exprs
2072 redef class ACrangeExpr
2073 redef fun accept_pretty_printer
(v
) do
2082 redef class AOrangeExpr
2083 redef fun accept_pretty_printer
(v
) do
2094 redef class AStringFormExpr
2095 redef fun accept_pretty_printer
(v
) do
2096 if not v
.break_strings
then
2097 # n_string.force_inline = true
2101 if v
.can_inline
(self) then
2102 n_string
.force_inline
= true
2105 var text
= n_string
.text
2108 while i
< text
.length
do
2111 if v
.current_length
>= v
.max_size
and i
<= text
.length
- 3 then
2127 v
.current_token
= n_string
.next_token
2132 redef class ASuperstringExpr
2133 redef fun accept_pretty_printer
(v
) do
2134 for n_expr
in n_exprs
do
2135 if not v
.break_strings
then
2136 n_expr
.force_inline
= true
2142 redef fun must_be_inline
do
2143 if super then return true
2145 if not n_exprs
.is_empty
then
2146 var first
= n_exprs
.first
2147 return first
isa AStringFormExpr and first
.n_string
.text
.has_prefix
("\"\
"\"")