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
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
!= target
do skip
151 # Visit `current_token`.
152 fun consume
(token
: String) do
153 assert current_token
.text
== token
157 # Is there token to visit between `current_token` and `target`?
158 fun need_catch_up
(target
: nullable Token): Bool do
159 if target
== null then return false
160 return current_token
!= target
163 # Visit all tokens between `current_token` and `target`.
164 fun catch_up
(target
: nullable ANode) do
165 if target
== null then return
166 if current_token
== null then return
168 if target
isa Token then
170 else if target
isa Prod then
171 token
= target
.first_token
.as(not null)
175 if current_token
.location
> token
.location
then return
176 while current_token
!= token
do visit current_token
179 # Visit all tokens between `current_token` and the end of line.
181 if current_token
isa TComment then
186 while current_token
isa TEol do skip
189 # The template under construction.
190 private var tpl
: nullable Template = null
192 # Current indent level.
195 # Size of a tabulation in spaces.
201 # Length of the current line.
202 var current_length
= 0
204 # Length of the previous line.
205 var previous_length
= 0
207 # Is the last line a blank line?
208 fun last_line_is_blank
: Bool do return previous_length
== 0
210 # Add `t` to current template.
211 fun add
(t
: String) do
212 if t
.is_empty
then return
213 while wait_addn
> 0 do
218 current_length
+= t
.length
223 if current_length
== 0 and last_line_is_blank
then return
224 previous_length
= current_length
229 # End of line chars are stored until another char is added.
230 # This avoid empty files with only a '`\n`'.
231 private var wait_addn
= 0
233 # Add `'\t' * indent`.
234 fun addt
do add
"\t" * indent
239 # Visit explicit receiver, implicit self will be ignored.
240 fun visit_recv
(n_expr
: AExpr) do
241 if not n_expr
isa AImplicitSelfExpr then
248 # Base framework redefs
250 redef class ANodes[E
]
251 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) do
253 var e_can_inline
= v
.can_inline
(e
)
256 if not e_can_inline
then
273 # Start visit of `self` using a `PrettyPrinterVisitor`
274 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) is abstract
276 # Collect the length (in `Char`) of the node.
277 private fun collect_length
: Int is abstract
279 # Is `self` printable in one line?
280 private fun is_inlinable
: Bool do return true
282 # Force `self` to be rendered as a block.
283 private var force_block
= false
285 # Does `self` have to be rendered as a block?
286 private fun must_be_block
: Bool do return force_block
288 # Force `self` to be rendered as a line.
289 private var force_inline
= false
291 # Does `self` have be rendered as a line?
292 private fun must_be_inline
: Bool do
293 if parent
!= null and parent
.must_be_inline
then return true
297 # Does `self` was written in one line before transformation?
298 private fun was_inline
: Bool is abstract
302 redef fun accept_pretty_printer
(v
) do
304 v
.current_token
= next_token
307 redef fun collect_length
do return text
.length
308 redef fun is_inlinable
do return true
309 redef fun was_inline
do return true
313 redef fun accept_pretty_printer
(v
) do v
.visit first_token
315 # The token where the production really start (skipping ADoc).
316 private fun start_token
: nullable Token do return first_token
318 # Collect all `TComment` contained in the production
319 # (between `start_token` and `end_token`).
320 private fun collect_comments
: Array[TComment] do
321 var res
= new Array[TComment]
322 if start_token
== null or last_token
== null then return res
323 var token
= start_token
325 while token
!= last_token
do
326 if token
isa TComment then res
.add token
327 token
= token
.next_token
333 redef fun collect_length
do
335 if start_token
== null or last_token
== null then return res
336 var token
= start_token
338 while token
!= last_token
do
339 res
+= token
.text
.length
340 token
= token
.next_token
343 res
+= token
.text
.length
347 redef fun was_inline
do
348 return start_token
.location
.line_start
== last_token
.location
.line_end
355 redef fun accept_pretty_printer
(v
) do
366 if is_last_in_group
then v
.addn
380 if next_token
isa TComment and is_first_in_group
then v
.addn
384 var prev_token
= self.prev_token
385 if prev_token
isa TComment and prev_token
.is_inline
and is_last_in_group
then v
.addn
392 # Is `self` part of an `ADoc`?
393 private fun is_adoc
: Bool do return parent
isa ADoc and parent
.parent
!= null
395 # Is `self` part of a licence?
396 private fun is_licence
: Bool do
397 var prev_token
= self.prev_token
399 if prev_token
== null then
401 else if prev_token
isa TComment then
402 return prev_token
.is_licence
408 # Is `self` starts and ends its line?
409 private fun is_inline
: Bool do
410 return self == first_real_token_in_line
and self == last_real_token_in_line
413 # Is `self` an orphan line (blank before and after)?
414 private fun is_orphan
: Bool do
415 return prev_token
isa TEol and
416 (prev_token
.prev_token
isa TEol or prev_token
.prev_token
isa TComment) and
420 # Is `self` the first comment of a group of comment?
421 private fun is_first_in_group
: Bool do return not prev_token
isa TComment
423 # Is `self` the last comment of a group of comments?
424 private fun is_last_in_group
: Bool do return not next_token
isa TComment
428 redef fun accept_pretty_printer
(v
) do for comment
in n_comment
do v
.visit comment
429 redef fun is_inlinable
do return n_comment
.length
<= 1
434 redef class AAnnotations
435 redef fun accept_pretty_printer
(v
) do
438 if v
.can_inline
(self) then
440 for n_item
in n_items
do
442 if n_item
!= n_items
.last
then
446 if not was_inline
then
448 if v
.current_token
isa TKwend then v
.skip
453 for n_item
in n_items
do
457 if n_item
!= n_items
.last
then v
.addn
463 redef fun is_inlinable
do
464 if not super then return false
465 for annot
in n_items
do if not annot
.is_inlinable
then return false
470 redef class AAnnotation
471 redef fun accept_pretty_printer
(v
) do
472 if n_visibility
!= null and not n_visibility
isa APublicVisibility then
477 if not n_args
.is_empty
then
478 if n_opar
== null then
489 redef class ATypeExpr
490 redef fun accept_pretty_printer
(v
) do v
.visit n_type
496 redef fun accept_pretty_printer
(v
) do
497 v
.catch_up start_token
500 if not n_imports
.is_empty
then
503 for n_import
in n_imports
do
509 if not n_extern_code_blocks
.is_empty
then
512 for n_extern_block
in n_extern_code_blocks
do
513 v
.catch_up n_extern_block
514 v
.visit n_extern_block
516 if n_extern_block
!= n_extern_code_blocks
.last
then v
.addn
519 if not n_classdefs
.is_empty
then v
.addn
522 if not n_classdefs
.is_empty
then
525 for n_classdef
in n_classdefs
do
526 v
.catch_up n_classdef
528 if n_classdef
!= n_classdefs
.last
then v
.addn
536 redef fun start_token
do
537 if n_moduledecl
!= null then return n_moduledecl
.first_token
538 if not n_imports
.is_empty
then return n_imports
.first
.first_token
539 if not n_classdefs
.is_empty
then return n_classdefs
.first
.first_token
543 redef fun is_inlinable
do return false
546 redef class AModuledecl
547 redef fun accept_pretty_printer
(v
) do
553 if n_annotations
!= null then
554 var annot_inline
= v
.can_inline
(n_annotations
)
555 v
.visit n_annotations
557 if not annot_inline
then
558 if v
.current_token
isa TKwend then
572 redef class AModuleName
573 redef fun accept_pretty_printer
(v
) do
574 for path
in n_path
do
583 redef class ANoImport
584 redef fun accept_pretty_printer
(v
) do
593 redef class AStdImport
594 redef fun accept_pretty_printer
(v
) do
595 if not n_visibility
isa APublicVisibility then
610 redef class AClassdef
611 redef fun accept_pretty_printer
(v
) do
612 for n_propdef
in n_propdefs
do
615 if n_propdef
.n_doc
!= null or not v
.can_inline
(n_propdef
) then
616 if n_propdef
!= n_propdefs
.first
then v
.addn
618 if n_propdef
!= n_propdefs
.last
then v
.addn
626 redef class AStdClassdef
627 redef fun accept_pretty_printer
(v
) do
629 var can_inline
= v
.can_inline
(self)
631 if not n_visibility
isa APublicVisibility then
636 if n_kwredef
!= null then
645 if not n_formaldefs
.is_empty
then
647 v
.visit_list n_formaldefs
651 if n_extern_code_block
!= null then
653 v
.visit n_extern_code_block
659 if not n_superclasses
.is_empty
then
660 for n_superclass
in n_superclasses
do
670 for n_superclass
in n_superclasses
do
671 v
.catch_up n_superclass
678 if not n_superclasses
.is_empty
and not n_propdefs
.is_empty
then
693 redef fun is_inlinable
do
694 if not super then return false
695 if not n_propdefs
.is_empty
then return false
696 if n_superclasses
.length
> 1 then return false
697 if not collect_comments
.is_empty
then return false
701 redef fun start_token
do
702 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
703 if n_kwredef
!= null then return n_kwredef
704 return n_classkind
.first_token
708 redef class AAbstractClasskind
709 redef fun accept_pretty_printer
(v
) do
716 redef class AExternClasskind
717 redef fun accept_pretty_printer
(v
) do
724 redef class AFormaldef
725 redef fun accept_pretty_printer
(v
) do
728 if n_type
!= null then
737 redef fun accept_pretty_printer
(v
) do
738 if n_kwnullable
!= null then
745 if not n_types
.is_empty
then
753 redef class ASuperclass
754 redef fun accept_pretty_printer
(v
) do
764 redef fun accept_pretty_printer
(v
) do
768 if not n_visibility
isa APublicVisibility then
773 if n_kwredef
!= null then
779 # Factorize annotations visit for all APropdef.
781 # Return true if annotations were inlined.
782 fun visit_annotations
(v
: PrettyPrinterVisitor, n_annotations
: nullable AAnnotations): Bool do
783 var res
= v
.can_inline
(n_annotations
)
784 if n_annotations
!= null then v
.visit n_annotations
788 # Factorize block visit for APropdefs.
790 # Were annotations printed inline? If so, we need to print the block differently.
791 fun visit_block
(v
: PrettyPrinterVisitor, n_block
: nullable AExpr, annot_inline
: Bool) do
792 if n_block
== null then return
793 while not v
.current_token
isa TKwdo do v
.skip
794 if n_annotations
!= null and not annot_inline
then
802 if v
.can_inline
(n_block
) then
805 if n_block
isa ABlockExpr then
806 if n_block
.n_expr
.is_empty
then
807 v
.visit n_block
.n_kwend
809 v
.visit n_block
.n_expr
.first
810 v
.current_token
= n_block
.n_kwend
815 if v
.current_token
isa TKwend then v
.skip
822 if n_block
isa ABlockExpr then
823 n_block
.force_block
= true
825 v
.catch_up n_block
.n_kwend
834 if n_block
isa ABlockExpr then
835 v
.visit n_block
.n_kwend
843 redef fun start_token
do
844 if n_doc
== null then return super
845 return n_doc
.last_token
.next_token
849 redef class AAttrPropdef
850 redef fun accept_pretty_printer
(v
) do
856 if n_type
!= null then
862 if n_expr
!= null then
869 var annot_inline
= visit_annotations
(v
, n_annotations
)
870 visit_block
(v
, n_block
, annot_inline
)
875 redef fun first_token
do
876 if n_doc
!= null then return n_doc
.first_token
877 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
878 if n_kwredef
!= null then return n_kwredef
882 redef fun is_inlinable
do return true
885 redef class ATypePropdef
886 redef fun accept_pretty_printer
(v
) do
894 visit_annotations
(v
, n_annotations
)
899 redef fun is_inlinable
do return true
902 redef class AMethPropdef
903 redef fun accept_pretty_printer
(v
) do
904 # TODO: Handle extern annotations
906 var before
= v
.indent
908 if n_kwinit
!= null then v
.visit n_kwinit
909 if n_kwmeth
!= null then v
.visit n_kwmeth
910 if n_kwnew
!= null then v
.visit n_kwnew
912 if not n_methid
== null then
919 var annot_inline
= visit_annotations
(v
, n_annotations
)
921 if n_extern_calls
!= null or n_extern_code_block
!= null then
923 if n_extern_calls
!= null then v
.visit n_extern_calls
924 if n_extern_code_block
!= null then v
.visit n_extern_code_block
927 visit_block
(v
, n_block
, annot_inline
)
929 assert v
.indent
== before
933 # * block is empty or can be inlined
934 # * contains no comments
935 redef fun is_inlinable
do
936 if not super then return false
937 if n_annotations
!= null and not n_annotations
.is_inlinable
then return false
938 if n_block
!= null and not n_block
.is_inlinable
then return false
939 if n_extern_calls
!= null and not n_extern_calls
.is_inlinable
then return false
940 if n_extern_code_block
!= null and not n_extern_code_block
.is_inlinable
then return false
941 if not collect_comments
.is_empty
then return false
946 redef class AMainMethPropdef
947 redef fun accept_pretty_printer
(v
) do
953 redef class ASignature
954 redef fun accept_pretty_printer
(v
) do
955 if not n_params
.is_empty
then
957 v
.visit_list n_params
961 if n_type
!= null then
970 redef fun accept_pretty_printer
(v
) do
973 if n_type
!= null then
979 if n_dotdotdot
!= null then v
.visit n_dotdotdot
985 redef class AExternCalls
986 redef fun accept_pretty_printer
(v
) do
987 var can_inline
= v
.can_inline
(self)
992 v
.visit_list n_extern_calls
998 v
.visit_list n_extern_calls
1005 redef class AFullPropExternCall
1006 redef fun accept_pretty_printer
(v
) do
1013 redef class ALocalPropExternCall
1014 redef fun accept_pretty_printer
(v
) do v
.visit n_methid
1017 redef class AInitPropExternCall
1018 redef fun accept_pretty_printer
(v
) do v
.visit n_type
1021 redef class ACastAsExternCall
1022 redef fun accept_pretty_printer
(v
) do
1032 redef class AAsNullableExternCall
1033 redef fun accept_pretty_printer
(v
) do
1038 v
.visit n_kwnullable
1042 redef class AAsNotNullableExternCall
1043 redef fun accept_pretty_printer
(v
) do
1050 v
.visit n_kwnullable
1054 redef class AExternCodeBlock
1055 redef fun accept_pretty_printer
(v
) do
1056 if n_in_language
!= null then
1057 v
.visit n_in_language
1061 v
.visit n_extern_code_segment
1064 redef fun is_inlinable
do
1065 if not super then return false
1066 return n_extern_code_segment
.is_inlinable
1070 redef class AInLanguage
1071 redef fun accept_pretty_printer
(v
) do
1078 redef class TExternCodeSegment
1079 redef fun accept_pretty_printer
(v
) do
1080 var can_inline
= v
.can_inline
(self)
1085 var text
= text
.substring
(2, text
.length
- 4)
1086 var lines
= text
.r_trim
.split
("\n")
1088 if text
.is_empty
then
1093 if not lines
.first
.trim
.is_empty
then
1101 for line
in lines
do
1110 v
.current_token
= next_token
1114 redef fun is_inlinable
do
1115 if not super then return false
1116 return location
.line_start
== location
.line_end
1122 redef class ABlockExpr
1123 redef fun accept_pretty_printer
(v
) do
1124 var before
= v
.indent
1125 var can_inline
= v
.can_inline
(self)
1127 if can_inline
and not n_expr
.is_empty
then
1128 v
.visit n_expr
.first
1131 for nexpr
in n_expr
do
1132 var expr_inline
= v
.can_inline
(nexpr
)
1133 if not expr_inline
and nexpr
!= n_expr
.first
then v
.addn
1139 if not expr_inline
and nexpr
!= n_expr
.last
then v
.addn
1143 assert v
.indent
== before
1146 redef fun is_inlinable
do
1147 if not super then return false
1148 if not collect_comments
.is_empty
then return false
1150 if not n_expr
.is_empty
then
1151 if n_expr
.length
> 1 then return false
1152 if not n_expr
.first
.is_inlinable
then return false
1160 redef fun accept_pretty_printer
(v
) do
1161 var before
= v
.indent
1162 var can_inline
= v
.can_inline
(self)
1166 if v
.can_inline
(n_expr
) then
1175 # skip comments before `then` token
1176 while not v
.current_token
isa TKwthen do v
.skip
1178 var n_else
= self.n_else
1182 if n_then
!= null then v
.visit n_then
1185 n_else
.force_inline
= true
1190 else if n_then
== null then
1194 v
.skip_to last_token
.last_real_token_in_line
1200 if n_then
!= null then
1201 if n_then
isa ABlockExpr then
1202 n_then
.force_block
= true
1212 while not v
.current_token
isa TKwelse do
1213 v
.consume v
.current_token
.text
1220 if n_else
isa AIfExpr then
1221 n_else
.force_block
= true
1229 if n_else
isa ABlockExpr then
1230 n_else
.force_block
= true
1238 if last_token
isa TKwend then
1239 v
.catch_up last_token
1250 if last_token
.location
>= v
.current_token
.location
then v
.catch_up last_token
1254 if v
.current_token
isa TKwend then v
.skip
1258 assert v
.indent
== before
1261 redef fun is_inlinable
do
1262 if not super then return false
1263 if n_then
!= null and not n_then
.is_inlinable
then return false
1264 var n_else
= self.n_else
1265 if (n_else
isa ABlockExpr and not n_else
.n_expr
.is_empty
) or
1266 (not n_else
isa ABlockExpr and n_else
!= null) then
1269 if not collect_comments
.is_empty
then return false
1273 # Does this `if` statement contains a `else` part?
1274 private fun has_else
(v
: PrettyPrinterVisitor): Bool do
1276 if n_else
== null then return false
1277 var n_kwelse
= collect_kwelse
1278 if n_kwelse
== null then return false
1280 if n_else
isa ABlockExpr then
1281 var comments
: Array[TComment]
1283 if n_then
== null then
1284 comments
= v
.collect_comments
(n_expr
.last_token
, n_else
.last_token
)
1286 comments
= v
.collect_comments
(n_then
.last_token
, n_else
.last_token
)
1289 if not comments
.is_empty
then return true
1290 return not n_else
.n_expr
.is_empty
1296 # Lookup for `else` token in `self`.
1297 private fun collect_kwelse
: nullable TKwelse do
1298 var token
= first_token
1300 while token
!= last_token
do
1301 if token
isa TKwelse then return token
1302 token
= token
.next_token
1309 # Used to factorize work on loops.
1310 private class ALoopHelper
1313 fun loop_block
: nullable ANode is abstract
1314 fun loop_label
: nullable ANode is abstract
1316 fun visit_loop_block
(v
: PrettyPrinterVisitor) do
1317 var n_block
= loop_block
1322 if n_block
isa ABlockExpr then
1323 n_block
.force_block
= true
1325 v
.catch_up n_block
.n_kwend
1328 v
.visit n_block
.n_kwend
1338 if loop_label
!= null then
1344 fun visit_loop_inline
(v
: PrettyPrinterVisitor) do
1345 var n_block
= loop_block
1348 if n_block
isa ABlockExpr then
1349 if n_block
.n_expr
.is_empty
then
1350 v
.visit n_block
.n_kwend
1352 v
.visit n_block
.n_expr
.first
1353 v
.current_token
= n_block
.n_kwend
1358 if v
.current_token
isa TKwend then v
.skip
1361 if loop_label
!= null then
1367 redef fun is_inlinable
do
1368 var n_block
= loop_block
1369 if not super then return false
1370 if n_block
isa ABlockExpr and not n_block
.is_inlinable
then return false
1371 if not collect_comments
.is_empty
then return false
1376 redef class ALoopExpr
1379 redef fun loop_block
do return n_block
1380 redef fun loop_label
do return n_label
1382 redef fun accept_pretty_printer
(v
) do
1383 var can_inline
= v
.can_inline
(self)
1385 if can_inline
then visit_loop_inline v
else visit_loop_block v
1389 redef class AWhileExpr
1392 redef fun loop_block
do return n_block
1393 redef fun loop_label
do return n_label
1395 redef fun accept_pretty_printer
(v
) do
1396 var can_inline
= v
.can_inline
(self)
1402 if can_inline
then visit_loop_inline v
else visit_loop_block v
1409 redef fun loop_block
do return n_block
1410 redef fun loop_label
do return n_label
1412 redef fun accept_pretty_printer
(v
) do
1413 var can_inline
= v
.can_inline
(self)
1415 if can_inline
then visit_loop_inline v
else visit_loop_block v
1419 redef class AForExpr
1422 redef fun loop_block
do return n_block
1423 redef fun loop_label
do return n_label
1425 redef fun accept_pretty_printer
(v
) do
1426 var can_inline
= v
.can_inline
(self)
1430 for n_id
in n_ids
do
1432 if n_id
!= n_ids
.last
then v
.add
", "
1441 if can_inline
then visit_loop_inline v
else visit_loop_block v
1445 redef class ABreakExpr
1446 redef fun accept_pretty_printer
(v
) do
1449 if n_expr
!= null then
1454 if n_label
!= null then
1460 redef fun is_inlinable
do return true
1463 redef class AContinueExpr
1464 redef fun accept_pretty_printer
(v
) do
1465 v
.visit n_kwcontinue
1467 if n_expr
!= null then
1472 if n_label
!= null then
1478 redef fun is_inlinable
do return true
1483 redef class ASendExpr
1484 redef fun is_inlinable
do return true
1487 redef class ACallExpr
1488 redef fun accept_pretty_printer
(v
) do
1489 var can_inline
= v
.can_inline
(self)
1492 if not n_expr
isa AImplicitSelfExpr and not can_inline
then
1499 if not n_args
.n_exprs
.is_empty
then
1500 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1502 if v
.current_token
isa TOpar then v
.skip
1503 v
.visit n_args
.n_exprs
.first
1504 if v
.current_token
isa TCpar then v
.skip
1506 if v
.current_token
isa TOpar then
1512 v
.visit_list n_args
.n_exprs
1513 if v
.current_token
isa TCpar then v
.consume
")"
1518 # Is the call alone on its line?
1519 fun is_stmt
: Bool do return parent
isa ABlockExpr
1522 redef class ACallAssignExpr
1523 redef fun accept_pretty_printer
(v
) do
1527 if not n_args
.n_exprs
.is_empty
then
1529 v
.visit_list n_args
.n_exprs
1540 redef class ACallReassignExpr
1541 redef fun accept_pretty_printer
(v
) do
1545 if not n_args
.n_exprs
.is_empty
then
1547 v
.visit_list n_args
.n_exprs
1558 redef class ABraExpr
1559 redef fun accept_pretty_printer
(v
) do
1562 if not n_args
.n_exprs
.is_empty
then
1564 v
.visit_list n_args
.n_exprs
1570 redef class ABraAssignExpr
1571 redef fun accept_pretty_printer
(v
) do
1574 if not n_args
.n_exprs
.is_empty
then
1576 v
.visit_list n_args
.n_exprs
1587 redef class ABraReassignExpr
1588 redef fun accept_pretty_printer
(v
) do
1591 if not n_args
.n_exprs
.is_empty
then
1593 v
.visit_list n_args
.n_exprs
1604 redef class AAssignMethid
1605 redef fun accept_pretty_printer
(v
) do
1611 redef class ABraMethid
1612 redef fun accept_pretty_printer
(v
) do
1618 redef class ABraassignMethid
1619 redef fun accept_pretty_printer
(v
) do
1626 redef class AInitExpr
1627 redef fun accept_pretty_printer
(v
) do
1628 if not n_expr
isa AImplicitSelfExpr then
1635 if not n_args
.n_exprs
.is_empty
then
1637 v
.visit_list n_args
.n_exprs
1643 redef class ANewExpr
1644 redef fun accept_pretty_printer
(v
) do
1645 var can_inline
= v
.can_inline
(self)
1650 if n_id
!= null then
1653 if not can_inline
then
1663 if not n_args
.n_exprs
.is_empty
then
1665 v
.visit_list n_args
.n_exprs
1670 redef fun is_inlinable
do return true
1675 redef class AAttrExpr
1676 redef fun accept_pretty_printer
(v
) do
1681 redef fun is_inlinable
do return true
1684 redef class AAttrAssignExpr
1685 redef fun accept_pretty_printer
(v
) do
1695 redef class AAttrReassignExpr
1696 redef fun accept_pretty_printer
(v
) do
1708 redef class AVardeclExpr
1709 redef fun accept_pretty_printer
(v
) do
1714 if n_type
!= null then
1720 if n_expr
!= null then
1728 redef fun is_inlinable
do return true
1731 redef class AVarAssignExpr
1732 redef fun accept_pretty_printer
(v
) do
1741 redef class AAssertExpr
1742 redef fun accept_pretty_printer
(v
) do
1743 var can_inline
= v
.can_inline
(self)
1746 if n_id
!= null then
1754 var n_else
= self.n_else
1756 if n_else
!= null then
1767 if n_else
isa ABlockExpr then
1768 n_else
.force_block
= true
1772 v
.visit n_else
.n_kwend
1785 redef fun is_inlinable
do
1786 if not super then return false
1787 if n_else
!= null and not n_else
.is_inlinable
then return false
1792 redef class AReturnExpr
1793 redef fun accept_pretty_printer
(v
) do
1796 if n_expr
!= null then
1803 redef class ASuperExpr
1804 redef fun accept_pretty_printer
(v
) do
1807 if not n_args
.n_exprs
.is_empty
then
1808 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1810 if v
.current_token
isa TOpar then v
.skip
1811 v
.visit n_args
.n_exprs
.first
1812 if v
.current_token
isa TCpar then v
.skip
1814 if v
.current_token
isa TOpar then
1820 v
.visit_list n_args
.n_exprs
1821 if v
.current_token
isa TCpar then v
.consume
")"
1826 # Is the call alone on its line?
1827 fun is_stmt
: Bool do return self.first_token
.is_starting_line
1829 redef fun is_inlinable
do return true
1832 redef class AOnceExpr
1833 redef fun accept_pretty_printer
(v
) do
1839 redef fun is_inlinable
do return true
1842 redef class AAbortExpr
1843 redef fun accept_pretty_printer
(v
) do v
.visit n_kwabort
1844 redef fun is_inlinable
do return true
1847 redef class ANotExpr
1848 redef fun accept_pretty_printer
(v
) do
1855 redef class AAsCastExpr
1856 redef fun accept_pretty_printer
(v
) do
1866 redef class AAsNotnullExpr
1867 redef fun accept_pretty_printer
(v
) do
1881 # Used to factorize work on Or, And, Implies and Binop expressions.
1882 private class ABinOpHelper
1885 fun bin_expr1
: AExpr is abstract
1886 fun bin_expr2
: AExpr is abstract
1889 fun bin_op
: String is abstract
1891 redef fun accept_pretty_printer
(v
) do
1892 var can_inline
= v
.can_inline
(self)
1894 if not can_inline
then
1895 if (self isa ABinopExpr and bin_expr1
isa ABinopExpr) or
1896 (self isa AAndExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr)) or
1897 (self isa AOrExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr))
1899 bin_expr1
.force_block
= true
1920 redef class AAndExpr
1923 redef fun bin_expr1
do return n_expr
1924 redef fun bin_expr2
do return n_expr2
1925 redef fun bin_op
do return "and"
1931 redef fun bin_expr1
do return n_expr
1932 redef fun bin_expr2
do return n_expr2
1933 redef fun bin_op
do return "or"
1936 redef class AImpliesExpr
1939 redef fun bin_expr1
do return n_expr
1940 redef fun bin_expr2
do return n_expr2
1941 redef fun bin_op
do return "implies"
1944 redef class ABinopExpr
1947 redef fun bin_expr1
do return n_expr
1948 redef fun bin_expr2
do return n_expr2
1952 redef fun bin_op
do return "=="
1956 redef fun bin_op
do return ">="
1960 redef fun bin_op
do return ">>"
1964 redef fun bin_op
do return ">"
1968 redef fun bin_op
do return "<="
1972 redef fun bin_op
do return "<<"
1976 redef fun bin_op
do return "<"
1979 redef class AMinusExpr
1980 redef fun bin_op
do return "-"
1984 redef fun bin_op
do return "!="
1987 redef class APercentExpr
1988 redef fun bin_op
do return "%"
1991 redef class APlusExpr
1992 redef fun bin_op
do return "+"
1995 redef class ASlashExpr
1996 redef fun bin_op
do return "/"
1999 redef class AStarExpr
2000 redef fun bin_op
do return "*"
2003 redef class AStarstarExpr
2004 redef fun bin_op
do return "**"
2007 redef class AStarshipExpr
2008 redef fun bin_op
do return "<=>"
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 AUminusExpr
2038 redef fun accept_pretty_printer
(v
) do
2044 redef class ANullExpr
2045 redef fun accept_pretty_printer
(v
) do v
.visit n_kwnull
2046 redef fun is_inlinable
do return true
2049 redef class AParExpr
2050 redef fun accept_pretty_printer
(v
) do
2057 redef class AArrayExpr
2058 redef fun accept_pretty_printer
(v
) do
2060 v
.visit_list n_exprs
2065 redef class ACrangeExpr
2066 redef fun accept_pretty_printer
(v
) do
2075 redef class AOrangeExpr
2076 redef fun accept_pretty_printer
(v
) do
2087 redef class AStringFormExpr
2088 redef fun accept_pretty_printer
(v
) do
2089 var can_inline
= v
.can_inline
(self)
2094 var text
= n_string
.text
2097 while i
< text
.length
do
2100 if v
.current_length
>= v
.max_size
and i
<= text
.length
- 3 then
2112 v
.current_token
= n_string
.next_token
2117 redef class ASuperstringExpr
2118 redef fun accept_pretty_printer
(v
) do
2119 for n_expr
in n_exprs
do v
.visit n_expr
2122 redef fun must_be_inline
do
2123 if super then return true
2125 if not n_exprs
.is_empty
then
2126 var first
= n_exprs
.first
2127 return first
isa AStringFormExpr and first
.n_string
.text
.has_prefix
("\"\
"\"")