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 # Visit `current_token`.
169 fun consume
(token
: String) do
170 if current_token
.text
== token
then else current_token
.debug
("Got `{current_token.text}`; expected `{token}`.")
174 # Is there token to visit between `current_token` and `target`?
175 fun need_catch_up
(target
: nullable Token): Bool do
176 if target
== null then return false
177 return current_token
!= target
180 # Visit all tokens between `current_token` and `target`.
181 fun catch_up
(target
: nullable ANode) do
182 if target
== null then return
183 if current_token
== null then return
185 if target
isa Token then
187 else if target
isa Prod then
188 token
= target
.first_token
.as(not null)
192 if current_token
.location
> token
.location
then return
193 while current_token
!= token
do visit current_token
196 # Visit all tokens between `current_token` and the end of line.
198 if current_token
isa TComment then
203 while current_token
isa TEol do visit
(current_token
)
206 # The template under construction.
207 private var tpl
: nullable Template = null
209 # Current indent level.
212 # Size of a tabulation in spaces.
218 # Length of the current line.
219 var current_length
= 0
221 # Length of the previous line.
222 var previous_length
= 0
224 # Is the last line a blank line?
225 fun last_line_is_blank
: Bool do return previous_length
== 0
227 # Add `t` to current template.
228 fun add
(t
: String) do
229 if t
.is_empty
then return
230 while wait_addn
> 0 do
235 current_length
+= t
.length
240 if current_length
== 0 and last_line_is_blank
then return
241 previous_length
= current_length
243 if skip_empty
then wait_addn
+= 1
246 # Perform `addn` even if not `skip_empty`.
248 if current_length
== 0 and last_line_is_blank
then return
249 previous_length
= current_length
254 # End of line chars are stored until another char is added.
255 # This avoid empty files with only a '`\n`'.
256 private var wait_addn
= 0
258 # Add `'\t' * indent`.
259 fun addt
do add
"\t" * indent
264 # Visit explicit receiver, implicit self will be ignored.
265 fun visit_recv
(n_expr
: AExpr) do
266 if not n_expr
isa AImplicitSelfExpr then
272 # Do we break string literals that are too long?
273 var break_strings
= false is public
writable
275 # Do we force `do` to be on the same line as the method signature?
276 var inline_do
= false is public
writable
278 # Do we force the deletion of empty lines?
279 var skip_empty
= false is public
writable
282 # Base framework redefs
284 redef class ANodes[E
]
285 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) do
287 var e_can_inline
= v
.can_inline
(e
)
290 if not e_can_inline
then
307 # Start visit of `self` using a `PrettyPrinterVisitor`
308 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) is abstract
310 # Collect the length (in `Char`) of the node.
311 private fun collect_length
: Int is abstract
313 # Is `self` printable in one line?
314 private fun is_inlinable
: Bool do return true
316 # Force `self` to be rendered as a block.
317 private var force_block
= false
319 # Does `self` have to be rendered as a block?
320 private fun must_be_block
: Bool do return force_block
322 # Force `self` to be rendered as a line.
323 private var force_inline
= false
325 # Does `self` have be rendered as a line?
326 private fun must_be_inline
: Bool do
327 if parent
!= null and parent
.must_be_inline
then return true
331 # Does `self` was written in one line before transformation?
332 private fun was_inline
: Bool is abstract
336 redef fun accept_pretty_printer
(v
) do
338 v
.current_token
= next_token
341 redef fun collect_length
do return text
.length
342 redef fun is_inlinable
do return true
343 redef fun was_inline
do return true
347 redef fun accept_pretty_printer
(v
) do
352 v
.current_token
= next_token
358 redef fun accept_pretty_printer
(v
) do v
.visit first_token
360 # The token where the production really start (skipping ADoc).
361 private fun start_token
: nullable Token do return first_token
363 # Collect all `TComment` contained in the production
364 # (between `start_token` and `end_token`).
365 private fun collect_comments
: Array[TComment] do
366 var res
= new Array[TComment]
367 if start_token
== null or last_token
== null then return res
368 var token
= start_token
370 while token
!= last_token
do
371 if token
isa TComment then res
.add token
372 token
= token
.next_token
378 redef fun collect_length
do
380 if start_token
== null or last_token
== null then return res
381 var token
= start_token
383 while token
!= last_token
do
384 res
+= token
.text
.length
385 token
= token
.next_token
388 res
+= token
.text
.length
392 redef fun was_inline
do
393 return start_token
.location
.line_start
== last_token
.location
.line_end
400 redef fun accept_pretty_printer
(v
) do
411 if is_last_in_group
then v
.addn
425 if next_token
isa TComment and is_first_in_group
then v
.addn
429 var prev_token
= self.prev_token
430 if prev_token
isa TComment and prev_token
.is_inline
and is_last_in_group
then v
.addn
435 if not v
.skip_empty
then v
.forcen
438 # Is `self` part of an `ADoc`?
439 private fun is_adoc
: Bool do return parent
isa ADoc and parent
.parent
!= null
441 # Is `self` part of a licence?
442 private fun is_licence
: Bool do
443 var prev_token
= self.prev_token
445 if prev_token
== null then
447 else if prev_token
isa TComment then
448 return prev_token
.is_licence
454 # Is `self` starts and ends its line?
455 private fun is_inline
: Bool do
456 return self == first_real_token_in_line
and self == last_real_token_in_line
459 # Is `self` an orphan line (blank before and after)?
460 private fun is_orphan
: Bool do
461 return prev_token
isa TEol and
462 (prev_token
.prev_token
isa TEol or prev_token
.prev_token
isa TComment) and
466 # Is `self` the first comment of a group of comment?
467 private fun is_first_in_group
: Bool do return not prev_token
isa TComment
469 # Is `self` the last comment of a group of comments?
470 private fun is_last_in_group
: Bool do return not next_token
isa TComment
474 redef fun accept_pretty_printer
(v
) do for comment
in n_comment
do v
.visit comment
475 redef fun is_inlinable
do return n_comment
.length
<= 1
480 redef class AAnnotations
481 redef fun accept_pretty_printer
(v
) do
484 if v
.can_inline
(self) then
486 for n_item
in n_items
do
488 if n_item
!= n_items
.last
then
492 if not was_inline
then
494 if v
.current_token
isa TKwend then v
.skip
499 for n_item
in n_items
do
503 if n_item
!= n_items
.last
then
515 redef fun is_inlinable
do
516 if not super then return false
517 for annot
in n_items
do if not annot
.is_inlinable
then return false
522 redef class AAnnotation
523 redef fun accept_pretty_printer
(v
) do
524 if n_visibility
!= null and not n_visibility
isa APublicVisibility then
533 redef class ATypeExpr
534 redef fun accept_pretty_printer
(v
) do v
.visit n_type
540 redef fun accept_pretty_printer
(v
) do
541 v
.catch_up start_token
544 if not n_imports
.is_empty
then
545 if v
.skip_empty
then v
.addn
547 for n_import
in n_imports
do
553 if not n_extern_code_blocks
.is_empty
then
556 for n_extern_block
in n_extern_code_blocks
do
557 v
.catch_up n_extern_block
558 v
.visit n_extern_block
560 if n_extern_block
!= n_extern_code_blocks
.last
then v
.addn
563 if not n_classdefs
.is_empty
then v
.addn
566 if not n_classdefs
.is_empty
then
567 if v
.skip_empty
then v
.addn
569 for n_classdef
in n_classdefs
do
570 v
.catch_up n_classdef
572 if n_classdef
!= n_classdefs
.last
then v
.addn
580 redef fun start_token
do
581 if n_moduledecl
!= null then return n_moduledecl
.first_token
582 if not n_imports
.is_empty
then return n_imports
.first
.first_token
583 if not n_classdefs
.is_empty
then return n_classdefs
.first
.first_token
587 redef fun is_inlinable
do return false
590 redef class AModuledecl
591 redef fun accept_pretty_printer
(v
) do
597 if n_annotations
!= null then
598 var annot_inline
= v
.can_inline
(n_annotations
)
599 v
.visit n_annotations
601 if not annot_inline
then
602 if v
.current_token
isa TKwend then
612 if v
.skip_empty
then v
.addn
616 redef class AModuleName
617 redef fun accept_pretty_printer
(v
) do
618 for path
in n_path
do
627 redef class ANoImport
628 redef fun accept_pretty_printer
(v
) do
633 if v
.skip_empty
then v
.addn
637 redef class AStdImport
638 redef fun accept_pretty_printer
(v
) do
639 if not n_visibility
isa APublicVisibility then
648 if v
.skip_empty
then v
.addn
654 redef class AClassdef
655 redef fun accept_pretty_printer
(v
) do
656 for n_propdef
in n_propdefs
do
659 if n_propdef
.n_doc
!= null or not v
.can_inline
(n_propdef
) then
660 if v
.skip_empty
and n_propdef
!= n_propdefs
.first
then v
.addn
662 if v
.skip_empty
and n_propdef
!= n_propdefs
.last
then v
.addn
670 redef class AStdClassdef
671 redef fun accept_pretty_printer
(v
) do
673 var can_inline
= v
.can_inline
(self)
675 if not n_visibility
isa APublicVisibility then
680 if n_kwredef
!= null then
689 if not n_formaldefs
.is_empty
then
691 v
.visit_list n_formaldefs
695 if n_extern_code_block
!= null then
697 v
.visit n_extern_code_block
703 if not n_propdefs
.is_empty
then
704 for n_superclass
in n_propdefs
do
711 if v
.skip_empty
then v
.addn
721 if v
.skip_empty
then v
.addn
725 redef fun is_inlinable
do
726 if not super then return false
727 # FIXME: repair pretty-printing one-liner classes
728 if n_propdefs
.length
> 0 then return false
729 #if n_propdefs.length == 1 and not n_propdefs.first isa ASuperPropdef then return false
730 if not collect_comments
.is_empty
then return false
734 redef fun start_token
do
735 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
736 if n_kwredef
!= null then return n_kwredef
737 return n_classkind
.first_token
741 redef class AAbstractClasskind
742 redef fun accept_pretty_printer
(v
) do
749 redef class AExternClasskind
750 redef fun accept_pretty_printer
(v
) do
757 redef class AFormaldef
758 redef fun accept_pretty_printer
(v
) do
761 if n_type
!= null then
770 redef fun accept_pretty_printer
(v
) do
771 if n_kwnullable
!= null then
778 if not n_types
.is_empty
then
789 redef fun accept_pretty_printer
(v
) do
793 if not n_visibility
isa nullable APublicVisibility then
798 if n_kwredef
!= null then
804 # Factorize annotations visit for all APropdef.
806 # Return true if annotations were inlined.
807 fun visit_annotations
(v
: PrettyPrinterVisitor, n_annotations
: nullable AAnnotations): Bool do
808 var res
= v
.can_inline
(n_annotations
)
809 if n_annotations
!= null then v
.visit n_annotations
813 # Factorize block visit for APropdefs.
815 # Were annotations printed inline? If so, we need to print the block differently.
816 fun visit_block
(v
: PrettyPrinterVisitor, n_block
: nullable AExpr, annot_inline
: Bool) do
817 # var can_inline = v.can_inline(n_block)
818 if n_block
== null then return
819 if n_annotations
!= null and not annot_inline
then
824 while not v
.current_token
isa TKwdo do v
.skip
826 var token
= v
.current_token
829 if token
isa TEol then
831 if not v
.can_inline
(n_block
) then
837 token
= v
.current_token
838 if token
isa TKwdo then break
840 if annot_inline
and do_inline
then v
.adds
843 if v
.can_inline
(n_block
) and do_inline
then
846 if n_block
isa ABlockExpr then
847 if n_block
.n_expr
.is_empty
then
848 v
.visit n_block
.n_kwend
850 v
.visit n_block
.n_expr
.first
851 v
.current_token
= n_block
.n_kwend
856 if v
.current_token
isa TKwend then v
.skip
867 if n_block
isa ABlockExpr then
868 n_block
.force_block
= true
870 v
.catch_up n_block
.n_kwend
879 if n_block
isa ABlockExpr then
880 v
.visit n_block
.n_kwend
888 redef fun start_token
do
889 if n_doc
== null then return super
890 return n_doc
.last_token
.next_token
894 redef class AAttrPropdef
895 redef fun accept_pretty_printer
(v
) do
901 if n_type
!= null then
907 if n_expr
!= null then
914 var annot_inline
= visit_annotations
(v
, n_annotations
)
915 visit_block
(v
, n_block
, annot_inline
)
920 redef fun first_token
do
921 if n_doc
!= null then return n_doc
.first_token
922 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
923 if n_kwredef
!= null then return n_kwredef
927 redef fun is_inlinable
do return true
930 redef class ATypePropdef
931 redef fun accept_pretty_printer
(v
) do
939 visit_annotations
(v
, n_annotations
)
944 redef fun is_inlinable
do return true
947 redef class AMethPropdef
948 redef fun accept_pretty_printer
(v
) do
949 # TODO: Handle extern annotations
951 var before
= v
.indent
953 if n_kwinit
!= null then v
.visit n_kwinit
954 if n_kwmeth
!= null then v
.visit n_kwmeth
955 if n_kwnew
!= null then v
.visit n_kwnew
957 if not n_methid
== null then
964 var annot_inline
= visit_annotations
(v
, n_annotations
)
966 if n_extern_calls
!= null or n_extern_code_block
!= null then
968 if n_extern_calls
!= null then v
.visit n_extern_calls
969 if n_extern_code_block
!= null then v
.visit n_extern_code_block
972 visit_block
(v
, n_block
, annot_inline
)
974 assert v
.indent
== before
978 # * block is empty or can be inlined
979 # * contains no comments
980 redef fun is_inlinable
do
981 if not super then return false
982 if n_annotations
!= null and not n_annotations
.is_inlinable
then return false
983 if n_block
!= null and not n_block
.is_inlinable
then return false
984 if n_extern_calls
!= null and not n_extern_calls
.is_inlinable
then return false
985 if n_extern_code_block
!= null and not n_extern_code_block
.is_inlinable
then return false
986 if not collect_comments
.is_empty
then return false
991 redef class AMainMethPropdef
992 redef fun accept_pretty_printer
(v
) do
994 if v
.skip_empty
then v
.addn
998 redef class ASuperPropdef
999 redef fun accept_pretty_printer
(v
) do
1004 visit_annotations
(v
, n_annotations
)
1009 redef fun is_inlinable
do return true
1012 redef class ASignature
1013 redef fun accept_pretty_printer
(v
) do
1014 if not n_params
.is_empty
then
1016 v
.visit_list n_params
1020 if n_type
!= null then
1029 redef fun accept_pretty_printer
(v
) do
1032 if n_type
!= null then
1038 if n_dotdotdot
!= null then v
.visit n_dotdotdot
1044 redef class AExternCalls
1045 redef fun accept_pretty_printer
(v
) do
1046 var can_inline
= v
.can_inline
(self)
1051 v
.visit_list n_extern_calls
1057 v
.visit_list n_extern_calls
1064 redef class AFullPropExternCall
1065 redef fun accept_pretty_printer
(v
) do
1072 redef class ALocalPropExternCall
1073 redef fun accept_pretty_printer
(v
) do v
.visit n_methid
1076 redef class AInitPropExternCall
1077 redef fun accept_pretty_printer
(v
) do v
.visit n_type
1080 redef class ACastAsExternCall
1081 redef fun accept_pretty_printer
(v
) do
1091 redef class AAsNullableExternCall
1092 redef fun accept_pretty_printer
(v
) do
1097 v
.visit n_kwnullable
1101 redef class AAsNotNullableExternCall
1102 redef fun accept_pretty_printer
(v
) do
1109 v
.visit n_kwnullable
1113 redef class AExternCodeBlock
1114 redef fun accept_pretty_printer
(v
) do
1115 if n_in_language
!= null then
1116 v
.visit n_in_language
1120 v
.visit n_extern_code_segment
1123 redef fun is_inlinable
do
1124 if not super then return false
1125 return n_extern_code_segment
.is_inlinable
1129 redef class AInLanguage
1130 redef fun accept_pretty_printer
(v
) do
1137 redef class TExternCodeSegment
1138 redef fun accept_pretty_printer
(v
) do
1139 var can_inline
= v
.can_inline
(self)
1144 var text
= text
.substring
(2, text
.length
- 4)
1145 var lines
= text
.r_trim
.split
("\n")
1147 if text
.is_empty
then
1152 if not lines
.first
.trim
.is_empty
then
1160 for line
in lines
do
1169 v
.current_token
= next_token
1173 redef fun is_inlinable
do
1174 if not super then return false
1175 return location
.line_start
== location
.line_end
1181 redef class ABlockExpr
1182 redef fun accept_pretty_printer
(v
) do
1183 var before
= v
.indent
1184 var can_inline
= v
.can_inline
(self)
1186 if can_inline
and not n_expr
.is_empty
then
1187 v
.visit n_expr
.first
1190 for nexpr
in n_expr
do
1191 var expr_inline
= v
.can_inline
(nexpr
)
1192 if not expr_inline
and nexpr
!= n_expr
.first
then v
.addn
1198 if not expr_inline
and nexpr
!= n_expr
.last
then v
.addn
1202 assert v
.indent
== before
1205 redef fun is_inlinable
do
1206 if not super then return false
1207 if not collect_comments
.is_empty
then return false
1209 if not n_expr
.is_empty
then
1210 if n_expr
.length
> 1 then return false
1211 if not n_expr
.first
.is_inlinable
then return false
1219 redef fun accept_pretty_printer
(v
) do
1220 var before
= v
.indent
1221 var can_inline
= v
.can_inline
(self)
1225 if v
.can_inline
(n_expr
) then
1234 # skip comments before `then` token
1235 while not v
.current_token
isa TKwthen do v
.skip
1237 var n_else
= self.n_else
1241 if n_then
!= null then v
.visit n_then
1244 n_else
.force_inline
= true
1249 else if n_then
== null then
1252 v
.skip_to last_token
.last_real_token_in_line
1257 else if not v
.skip_empty
and n_then
!= null and
1258 n_then
.was_inline
and
1259 n_then
.location
.line_end
== location
.line_start
then
1260 v
.forcen
# Xymus fucking syntax
1266 if n_then
!= null then
1267 if n_then
isa ABlockExpr then
1268 n_then
.force_block
= true
1273 if n_then
.was_inline
then
1282 while not v
.current_token
isa TKwelse do
1283 v
.consume v
.current_token
.text
1290 if n_else
isa AIfExpr then
1291 n_else
.force_block
= true
1303 if n_else
isa ABlockExpr then
1304 n_else
.force_block
= true
1309 if n_else
.was_inline
then
1316 if last_token
isa TKwend then
1317 v
.catch_up last_token
1328 if last_token
.location
>= v
.current_token
.location
then v
.catch_up last_token
1332 if v
.current_token
isa TKwend then v
.skip
1336 assert v
.indent
== before
1339 redef fun is_inlinable
do
1340 if not super then return false
1341 if n_then
!= null and not n_then
.is_inlinable
then return false
1342 var n_else
= self.n_else
1343 if (n_else
isa ABlockExpr and not n_else
.n_expr
.is_empty
) or
1344 (not n_else
isa ABlockExpr and n_else
!= null) then
1347 if not collect_comments
.is_empty
then return false
1351 # Does this `if` statement contains a `else` part?
1352 private fun has_else
(v
: PrettyPrinterVisitor): Bool do
1354 if n_else
== null then return false
1355 var n_kwelse
= collect_kwelse
1356 if n_kwelse
== null then return false
1358 if n_else
isa ABlockExpr then
1359 var comments
: Array[TComment]
1361 if n_then
== null then
1362 comments
= v
.collect_comments
(n_expr
.last_token
, n_else
.last_token
)
1364 comments
= v
.collect_comments
(n_then
.last_token
, n_else
.last_token
)
1367 if not comments
.is_empty
then return true
1368 return not n_else
.n_expr
.is_empty
1374 # Lookup for `else` token in `self`.
1375 private fun collect_kwelse
: nullable TKwelse do
1376 var token
= first_token
1378 while token
!= last_token
do
1379 if token
isa TKwelse then return token
1380 token
= token
.next_token
1387 # Used to factorize work on loops.
1388 private class ALoopHelper
1391 fun loop_block
: nullable ANode is abstract
1392 fun loop_label
: nullable ANode is abstract
1394 fun visit_loop_block
(v
: PrettyPrinterVisitor) do
1395 var n_block
= loop_block
1400 if n_block
isa ABlockExpr then
1401 n_block
.force_block
= true
1403 v
.catch_up n_block
.n_kwend
1406 v
.visit n_block
.n_kwend
1416 if loop_label
!= null then
1422 fun visit_loop_inline
(v
: PrettyPrinterVisitor) do
1423 var n_block
= loop_block
1426 if n_block
isa ABlockExpr then
1427 if n_block
.n_expr
.is_empty
then
1428 v
.visit n_block
.n_kwend
1430 v
.visit n_block
.n_expr
.first
1431 v
.current_token
= n_block
.n_kwend
1436 if v
.current_token
isa TKwend then v
.skip
1439 if loop_label
!= null then
1445 redef fun is_inlinable
do
1446 var n_block
= loop_block
1447 if not super then return false
1448 if n_block
isa ABlockExpr and not n_block
.is_inlinable
then return false
1449 if not collect_comments
.is_empty
then return false
1454 redef class ALoopExpr
1457 redef fun loop_block
do return n_block
1458 redef fun loop_label
do return n_label
1460 redef fun accept_pretty_printer
(v
) do
1461 var can_inline
= v
.can_inline
(self)
1463 if can_inline
then visit_loop_inline v
else visit_loop_block v
1467 redef class AWhileExpr
1470 redef fun loop_block
do return n_block
1471 redef fun loop_label
do return n_label
1473 redef fun accept_pretty_printer
(v
) do
1474 var can_inline
= v
.can_inline
(self)
1480 if can_inline
then visit_loop_inline v
else visit_loop_block v
1487 redef fun loop_block
do return n_block
1488 redef fun loop_label
do return n_label
1490 redef fun accept_pretty_printer
(v
) do
1491 var can_inline
= v
.can_inline
(self)
1493 if can_inline
then visit_loop_inline v
else visit_loop_block v
1497 redef class AForExpr
1500 redef fun loop_block
do return n_block
1501 redef fun loop_label
do return n_label
1503 redef fun accept_pretty_printer
(v
) do
1504 var can_inline
= v
.can_inline
(self)
1508 for n_id
in n_ids
do
1510 if n_id
!= n_ids
.last
then v
.add
", "
1519 if can_inline
then visit_loop_inline v
else visit_loop_block v
1523 redef class ABreakExpr
1524 redef fun accept_pretty_printer
(v
) do
1527 if n_expr
!= null then
1532 if n_label
!= null then
1538 redef fun is_inlinable
do return true
1541 redef class AContinueExpr
1542 redef fun accept_pretty_printer
(v
) do
1543 v
.visit n_kwcontinue
1545 if n_expr
!= null then
1550 if n_label
!= null then
1556 redef fun is_inlinable
do return true
1561 redef class ASendExpr
1562 redef fun is_inlinable
do return true
1565 redef class ACallExpr
1566 redef fun accept_pretty_printer
(v
) do
1567 var can_inline
= v
.can_inline
(self)
1570 if not n_expr
isa AImplicitSelfExpr and not can_inline
then
1577 if not n_args
.n_exprs
.is_empty
then
1578 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1580 if v
.current_token
isa TOpar then v
.skip
1581 v
.visit n_args
.n_exprs
.first
1582 if v
.current_token
isa TCpar then v
.skip
1584 v
.visit_args n_args
.n_exprs
1589 # Is the call alone on its line?
1590 fun is_stmt
: Bool do return parent
isa ABlockExpr
1593 redef class ACallAssignExpr
1594 redef fun accept_pretty_printer
(v
) do
1598 if not n_args
.n_exprs
.is_empty
then
1600 v
.visit_list n_args
.n_exprs
1611 redef class ACallReassignExpr
1612 redef fun accept_pretty_printer
(v
) do
1616 if not n_args
.n_exprs
.is_empty
then
1618 v
.visit_list n_args
.n_exprs
1629 redef class ABraExpr
1630 redef fun accept_pretty_printer
(v
) do
1633 if not n_args
.n_exprs
.is_empty
then
1635 v
.visit_list n_args
.n_exprs
1641 redef class ABraAssignExpr
1642 redef fun accept_pretty_printer
(v
) do
1645 if not n_args
.n_exprs
.is_empty
then
1647 v
.visit_list n_args
.n_exprs
1658 redef class ABraReassignExpr
1659 redef fun accept_pretty_printer
(v
) do
1662 if not n_args
.n_exprs
.is_empty
then
1664 v
.visit_list n_args
.n_exprs
1675 redef class AAssignMethid
1676 redef fun accept_pretty_printer
(v
) do
1682 redef class ABraMethid
1683 redef fun accept_pretty_printer
(v
) do
1689 redef class ABraassignMethid
1690 redef fun accept_pretty_printer
(v
) do
1697 redef class AInitExpr
1698 redef fun accept_pretty_printer
(v
) do
1699 if not n_expr
isa AImplicitSelfExpr then
1705 v
.visit_args n_args
.n_exprs
1709 redef class ANewExpr
1710 redef fun accept_pretty_printer
(v
) do
1711 var can_inline
= v
.can_inline
(self)
1716 if n_id
!= null then
1719 if not can_inline
then
1729 v
.visit_args n_args
.n_exprs
1732 redef fun is_inlinable
do return true
1737 redef class AAttrExpr
1738 redef fun accept_pretty_printer
(v
) do
1743 redef fun is_inlinable
do return true
1746 redef class AAttrAssignExpr
1747 redef fun accept_pretty_printer
(v
) do
1757 redef class AAttrReassignExpr
1758 redef fun accept_pretty_printer
(v
) do
1770 redef class AVardeclExpr
1771 redef fun accept_pretty_printer
(v
) do
1776 if n_type
!= null then
1782 if n_expr
!= null then
1790 redef fun is_inlinable
do return true
1793 redef class AVarAssignExpr
1794 redef fun accept_pretty_printer
(v
) do
1803 redef class AAssertExpr
1804 redef fun accept_pretty_printer
(v
) do
1805 var can_inline
= v
.can_inline
(self)
1808 if n_id
!= null then
1816 var n_else
= self.n_else
1818 if n_else
!= null then
1829 if n_else
isa ABlockExpr then
1830 n_else
.force_block
= true
1834 v
.visit n_else
.n_kwend
1847 redef fun is_inlinable
do
1848 if not super then return false
1849 if n_else
!= null and not n_else
.is_inlinable
then return false
1854 redef class AReturnExpr
1855 redef fun accept_pretty_printer
(v
) do
1858 if n_expr
!= null then
1865 redef class ASuperExpr
1866 redef fun accept_pretty_printer
(v
) do
1869 if not n_args
.n_exprs
.is_empty
then
1870 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1872 if v
.current_token
isa TOpar then v
.skip
1873 v
.visit n_args
.n_exprs
.first
1874 if v
.current_token
isa TCpar then v
.skip
1876 v
.visit_args n_args
.n_exprs
1881 # Is the call alone on its line?
1882 fun is_stmt
: Bool do return self.first_token
.is_starting_line
1884 redef fun is_inlinable
do return true
1887 redef class AOnceExpr
1888 redef fun accept_pretty_printer
(v
) do
1894 redef fun is_inlinable
do return true
1897 redef class AAbortExpr
1898 redef fun accept_pretty_printer
(v
) do v
.visit n_kwabort
1899 redef fun is_inlinable
do return true
1902 redef class ANotExpr
1903 redef fun accept_pretty_printer
(v
) do
1910 redef class AAsCastExpr
1911 redef fun accept_pretty_printer
(v
) do
1921 redef class AAsNotnullExpr
1922 redef fun accept_pretty_printer
(v
) do
1936 # Used to factorize work on Or, And, Implies and Binop expressions.
1937 private class ABinOpHelper
1940 fun bin_expr1
: AExpr is abstract
1941 fun bin_expr2
: AExpr is abstract
1944 fun bin_op
: String is abstract
1946 redef fun accept_pretty_printer
(v
) do
1947 var can_inline
= v
.can_inline
(self)
1949 if not can_inline
then
1950 if (self isa ABinopExpr and bin_expr1
isa ABinopExpr) or
1951 (self isa AAndExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr)) or
1952 (self isa AOrExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr))
1954 bin_expr1
.force_block
= true
1975 redef class AAndExpr
1978 redef fun bin_expr1
do return n_expr
1979 redef fun bin_expr2
do return n_expr2
1980 redef fun bin_op
do return "and"
1986 redef fun bin_expr1
do return n_expr
1987 redef fun bin_expr2
do return n_expr2
1988 redef fun bin_op
do return "or"
1991 redef class AImpliesExpr
1994 redef fun bin_expr1
do return n_expr
1995 redef fun bin_expr2
do return n_expr2
1996 redef fun bin_op
do return "implies"
1999 redef class ABinopExpr
2002 redef fun bin_expr1
do return n_expr
2003 redef fun bin_expr2
do return n_expr2
2004 redef fun bin_op
do return operator
2007 redef class AIsaExpr
2008 redef fun accept_pretty_printer
(v
) do
2017 redef class AOrElseExpr
2018 redef fun accept_pretty_printer
(v
) do
2028 redef fun is_inlinable
do return true
2033 redef class AUplusExpr
2034 redef fun accept_pretty_printer
(v
) do
2040 redef class AUminusExpr
2041 redef fun accept_pretty_printer
(v
) do
2047 redef class ANullExpr
2048 redef fun accept_pretty_printer
(v
) do v
.visit n_kwnull
2049 redef fun is_inlinable
do return true
2052 redef class AParExpr
2053 redef fun accept_pretty_printer
(v
) do
2060 redef class AArrayExpr
2061 redef fun accept_pretty_printer
(v
) do
2063 v
.visit_list n_exprs
2068 redef class ACrangeExpr
2069 redef fun accept_pretty_printer
(v
) do
2078 redef class AOrangeExpr
2079 redef fun accept_pretty_printer
(v
) do
2090 redef class AStringFormExpr
2091 redef fun accept_pretty_printer
(v
) do
2092 if not v
.break_strings
then
2093 # n_string.force_inline = true
2097 if v
.can_inline
(self) then
2098 n_string
.force_inline
= true
2101 var text
= n_string
.text
2104 while i
< text
.length
do
2107 if v
.current_length
>= v
.max_size
and i
<= text
.length
- 3 then
2123 v
.current_token
= n_string
.next_token
2128 redef class ASuperstringExpr
2129 redef fun accept_pretty_printer
(v
) do
2130 for n_expr
in n_exprs
do
2131 if not v
.break_strings
then
2132 n_expr
.force_inline
= true
2138 redef fun must_be_inline
do
2139 if super then return true
2141 if not n_exprs
.is_empty
then
2142 var first
= n_exprs
.first
2143 return first
isa AStringFormExpr and first
.n_string
.text
.has_prefix
("\"\
"\"")