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
247 # Do we break string literals that are too long?
248 var break_strings
= false is public
writable
251 # Base framework redefs
253 redef class ANodes[E
]
254 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) do
256 var e_can_inline
= v
.can_inline
(e
)
259 if not e_can_inline
then
276 # Start visit of `self` using a `PrettyPrinterVisitor`
277 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) is abstract
279 # Collect the length (in `Char`) of the node.
280 private fun collect_length
: Int is abstract
282 # Is `self` printable in one line?
283 private fun is_inlinable
: Bool do return true
285 # Force `self` to be rendered as a block.
286 private var force_block
= false
288 # Does `self` have to be rendered as a block?
289 private fun must_be_block
: Bool do return force_block
291 # Force `self` to be rendered as a line.
292 private var force_inline
= false
294 # Does `self` have be rendered as a line?
295 private fun must_be_inline
: Bool do
296 if parent
!= null and parent
.must_be_inline
then return true
300 # Does `self` was written in one line before transformation?
301 private fun was_inline
: Bool is abstract
305 redef fun accept_pretty_printer
(v
) do
307 v
.current_token
= next_token
310 redef fun collect_length
do return text
.length
311 redef fun is_inlinable
do return true
312 redef fun was_inline
do return true
316 redef fun accept_pretty_printer
(v
) do v
.visit first_token
318 # The token where the production really start (skipping ADoc).
319 private fun start_token
: nullable Token do return first_token
321 # Collect all `TComment` contained in the production
322 # (between `start_token` and `end_token`).
323 private fun collect_comments
: Array[TComment] do
324 var res
= new Array[TComment]
325 if start_token
== null or last_token
== null then return res
326 var token
= start_token
328 while token
!= last_token
do
329 if token
isa TComment then res
.add token
330 token
= token
.next_token
336 redef fun collect_length
do
338 if start_token
== null or last_token
== null then return res
339 var token
= start_token
341 while token
!= last_token
do
342 res
+= token
.text
.length
343 token
= token
.next_token
346 res
+= token
.text
.length
350 redef fun was_inline
do
351 return start_token
.location
.line_start
== last_token
.location
.line_end
358 redef fun accept_pretty_printer
(v
) do
369 if is_last_in_group
then v
.addn
383 if next_token
isa TComment and is_first_in_group
then v
.addn
387 var prev_token
= self.prev_token
388 if prev_token
isa TComment and prev_token
.is_inline
and is_last_in_group
then v
.addn
395 # Is `self` part of an `ADoc`?
396 private fun is_adoc
: Bool do return parent
isa ADoc and parent
.parent
!= null
398 # Is `self` part of a licence?
399 private fun is_licence
: Bool do
400 var prev_token
= self.prev_token
402 if prev_token
== null then
404 else if prev_token
isa TComment then
405 return prev_token
.is_licence
411 # Is `self` starts and ends its line?
412 private fun is_inline
: Bool do
413 return self == first_real_token_in_line
and self == last_real_token_in_line
416 # Is `self` an orphan line (blank before and after)?
417 private fun is_orphan
: Bool do
418 return prev_token
isa TEol and
419 (prev_token
.prev_token
isa TEol or prev_token
.prev_token
isa TComment) and
423 # Is `self` the first comment of a group of comment?
424 private fun is_first_in_group
: Bool do return not prev_token
isa TComment
426 # Is `self` the last comment of a group of comments?
427 private fun is_last_in_group
: Bool do return not next_token
isa TComment
431 redef fun accept_pretty_printer
(v
) do for comment
in n_comment
do v
.visit comment
432 redef fun is_inlinable
do return n_comment
.length
<= 1
437 redef class AAnnotations
438 redef fun accept_pretty_printer
(v
) do
441 if v
.can_inline
(self) then
443 for n_item
in n_items
do
445 if n_item
!= n_items
.last
then
449 if not was_inline
then
451 if v
.current_token
isa TKwend then v
.skip
456 for n_item
in n_items
do
460 if n_item
!= n_items
.last
then v
.addn
466 redef fun is_inlinable
do
467 if not super then return false
468 for annot
in n_items
do if not annot
.is_inlinable
then return false
473 redef class AAnnotation
474 redef fun accept_pretty_printer
(v
) do
475 if n_visibility
!= null and not n_visibility
isa APublicVisibility then
480 if not n_args
.is_empty
then
481 if n_opar
== null then
492 redef class ATypeExpr
493 redef fun accept_pretty_printer
(v
) do v
.visit n_type
499 redef fun accept_pretty_printer
(v
) do
500 v
.catch_up start_token
503 if not n_imports
.is_empty
then
506 for n_import
in n_imports
do
512 if not n_extern_code_blocks
.is_empty
then
515 for n_extern_block
in n_extern_code_blocks
do
516 v
.catch_up n_extern_block
517 v
.visit n_extern_block
519 if n_extern_block
!= n_extern_code_blocks
.last
then v
.addn
522 if not n_classdefs
.is_empty
then v
.addn
525 if not n_classdefs
.is_empty
then
528 for n_classdef
in n_classdefs
do
529 v
.catch_up n_classdef
531 if n_classdef
!= n_classdefs
.last
then v
.addn
539 redef fun start_token
do
540 if n_moduledecl
!= null then return n_moduledecl
.first_token
541 if not n_imports
.is_empty
then return n_imports
.first
.first_token
542 if not n_classdefs
.is_empty
then return n_classdefs
.first
.first_token
546 redef fun is_inlinable
do return false
549 redef class AModuledecl
550 redef fun accept_pretty_printer
(v
) do
556 if n_annotations
!= null then
557 var annot_inline
= v
.can_inline
(n_annotations
)
558 v
.visit n_annotations
560 if not annot_inline
then
561 if v
.current_token
isa TKwend then
575 redef class AModuleName
576 redef fun accept_pretty_printer
(v
) do
577 for path
in n_path
do
586 redef class ANoImport
587 redef fun accept_pretty_printer
(v
) do
596 redef class AStdImport
597 redef fun accept_pretty_printer
(v
) do
598 if not n_visibility
isa APublicVisibility then
613 redef class AClassdef
614 redef fun accept_pretty_printer
(v
) do
615 for n_propdef
in n_propdefs
do
618 if n_propdef
.n_doc
!= null or not v
.can_inline
(n_propdef
) then
619 if n_propdef
!= n_propdefs
.first
then v
.addn
621 if n_propdef
!= n_propdefs
.last
then v
.addn
629 redef class AStdClassdef
630 redef fun accept_pretty_printer
(v
) do
632 var can_inline
= v
.can_inline
(self)
634 if not n_visibility
isa APublicVisibility then
639 if n_kwredef
!= null then
648 if not n_formaldefs
.is_empty
then
650 v
.visit_list n_formaldefs
654 if n_extern_code_block
!= null then
656 v
.visit n_extern_code_block
662 if not n_superclasses
.is_empty
then
663 for n_superclass
in n_superclasses
do
673 for n_superclass
in n_superclasses
do
674 v
.catch_up n_superclass
681 if not n_superclasses
.is_empty
and not n_propdefs
.is_empty
then
696 redef fun is_inlinable
do
697 if not super then return false
698 if not n_propdefs
.is_empty
then return false
699 if n_superclasses
.length
> 1 then return false
700 if not collect_comments
.is_empty
then return false
704 redef fun start_token
do
705 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
706 if n_kwredef
!= null then return n_kwredef
707 return n_classkind
.first_token
711 redef class AAbstractClasskind
712 redef fun accept_pretty_printer
(v
) do
719 redef class AExternClasskind
720 redef fun accept_pretty_printer
(v
) do
727 redef class AFormaldef
728 redef fun accept_pretty_printer
(v
) do
731 if n_type
!= null then
740 redef fun accept_pretty_printer
(v
) do
741 if n_kwnullable
!= null then
748 if not n_types
.is_empty
then
756 redef class ASuperclass
757 redef fun accept_pretty_printer
(v
) do
767 redef fun accept_pretty_printer
(v
) do
771 if not n_visibility
isa APublicVisibility then
776 if n_kwredef
!= null then
782 # Factorize annotations visit for all APropdef.
784 # Return true if annotations were inlined.
785 fun visit_annotations
(v
: PrettyPrinterVisitor, n_annotations
: nullable AAnnotations): Bool do
786 var res
= v
.can_inline
(n_annotations
)
787 if n_annotations
!= null then v
.visit n_annotations
791 # Factorize block visit for APropdefs.
793 # Were annotations printed inline? If so, we need to print the block differently.
794 fun visit_block
(v
: PrettyPrinterVisitor, n_block
: nullable AExpr, annot_inline
: Bool) do
795 if n_block
== null then return
796 while not v
.current_token
isa TKwdo do v
.skip
797 if n_annotations
!= null and not annot_inline
then
805 if v
.can_inline
(n_block
) then
808 if n_block
isa ABlockExpr then
809 if n_block
.n_expr
.is_empty
then
810 v
.visit n_block
.n_kwend
812 v
.visit n_block
.n_expr
.first
813 v
.current_token
= n_block
.n_kwend
818 if v
.current_token
isa TKwend then v
.skip
825 if n_block
isa ABlockExpr then
826 n_block
.force_block
= true
828 v
.catch_up n_block
.n_kwend
837 if n_block
isa ABlockExpr then
838 v
.visit n_block
.n_kwend
846 redef fun start_token
do
847 if n_doc
== null then return super
848 return n_doc
.last_token
.next_token
852 redef class AAttrPropdef
853 redef fun accept_pretty_printer
(v
) do
859 if n_type
!= null then
865 if n_expr
!= null then
872 var annot_inline
= visit_annotations
(v
, n_annotations
)
873 visit_block
(v
, n_block
, annot_inline
)
878 redef fun first_token
do
879 if n_doc
!= null then return n_doc
.first_token
880 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
881 if n_kwredef
!= null then return n_kwredef
885 redef fun is_inlinable
do return true
888 redef class ATypePropdef
889 redef fun accept_pretty_printer
(v
) do
897 visit_annotations
(v
, n_annotations
)
902 redef fun is_inlinable
do return true
905 redef class AMethPropdef
906 redef fun accept_pretty_printer
(v
) do
907 # TODO: Handle extern annotations
909 var before
= v
.indent
911 if n_kwinit
!= null then v
.visit n_kwinit
912 if n_kwmeth
!= null then v
.visit n_kwmeth
913 if n_kwnew
!= null then v
.visit n_kwnew
915 if not n_methid
== null then
922 var annot_inline
= visit_annotations
(v
, n_annotations
)
924 if n_extern_calls
!= null or n_extern_code_block
!= null then
926 if n_extern_calls
!= null then v
.visit n_extern_calls
927 if n_extern_code_block
!= null then v
.visit n_extern_code_block
930 visit_block
(v
, n_block
, annot_inline
)
932 assert v
.indent
== before
936 # * block is empty or can be inlined
937 # * contains no comments
938 redef fun is_inlinable
do
939 if not super then return false
940 if n_annotations
!= null and not n_annotations
.is_inlinable
then return false
941 if n_block
!= null and not n_block
.is_inlinable
then return false
942 if n_extern_calls
!= null and not n_extern_calls
.is_inlinable
then return false
943 if n_extern_code_block
!= null and not n_extern_code_block
.is_inlinable
then return false
944 if not collect_comments
.is_empty
then return false
949 redef class AMainMethPropdef
950 redef fun accept_pretty_printer
(v
) do
956 redef class ASignature
957 redef fun accept_pretty_printer
(v
) do
958 if not n_params
.is_empty
then
960 v
.visit_list n_params
964 if n_type
!= null then
973 redef fun accept_pretty_printer
(v
) do
976 if n_type
!= null then
982 if n_dotdotdot
!= null then v
.visit n_dotdotdot
988 redef class AExternCalls
989 redef fun accept_pretty_printer
(v
) do
990 var can_inline
= v
.can_inline
(self)
995 v
.visit_list n_extern_calls
1001 v
.visit_list n_extern_calls
1008 redef class AFullPropExternCall
1009 redef fun accept_pretty_printer
(v
) do
1016 redef class ALocalPropExternCall
1017 redef fun accept_pretty_printer
(v
) do v
.visit n_methid
1020 redef class AInitPropExternCall
1021 redef fun accept_pretty_printer
(v
) do v
.visit n_type
1024 redef class ACastAsExternCall
1025 redef fun accept_pretty_printer
(v
) do
1035 redef class AAsNullableExternCall
1036 redef fun accept_pretty_printer
(v
) do
1041 v
.visit n_kwnullable
1045 redef class AAsNotNullableExternCall
1046 redef fun accept_pretty_printer
(v
) do
1053 v
.visit n_kwnullable
1057 redef class AExternCodeBlock
1058 redef fun accept_pretty_printer
(v
) do
1059 if n_in_language
!= null then
1060 v
.visit n_in_language
1064 v
.visit n_extern_code_segment
1067 redef fun is_inlinable
do
1068 if not super then return false
1069 return n_extern_code_segment
.is_inlinable
1073 redef class AInLanguage
1074 redef fun accept_pretty_printer
(v
) do
1081 redef class TExternCodeSegment
1082 redef fun accept_pretty_printer
(v
) do
1083 var can_inline
= v
.can_inline
(self)
1088 var text
= text
.substring
(2, text
.length
- 4)
1089 var lines
= text
.r_trim
.split
("\n")
1091 if text
.is_empty
then
1096 if not lines
.first
.trim
.is_empty
then
1104 for line
in lines
do
1113 v
.current_token
= next_token
1117 redef fun is_inlinable
do
1118 if not super then return false
1119 return location
.line_start
== location
.line_end
1125 redef class ABlockExpr
1126 redef fun accept_pretty_printer
(v
) do
1127 var before
= v
.indent
1128 var can_inline
= v
.can_inline
(self)
1130 if can_inline
and not n_expr
.is_empty
then
1131 v
.visit n_expr
.first
1134 for nexpr
in n_expr
do
1135 var expr_inline
= v
.can_inline
(nexpr
)
1136 if not expr_inline
and nexpr
!= n_expr
.first
then v
.addn
1142 if not expr_inline
and nexpr
!= n_expr
.last
then v
.addn
1146 assert v
.indent
== before
1149 redef fun is_inlinable
do
1150 if not super then return false
1151 if not collect_comments
.is_empty
then return false
1153 if not n_expr
.is_empty
then
1154 if n_expr
.length
> 1 then return false
1155 if not n_expr
.first
.is_inlinable
then return false
1163 redef fun accept_pretty_printer
(v
) do
1164 var before
= v
.indent
1165 var can_inline
= v
.can_inline
(self)
1169 if v
.can_inline
(n_expr
) then
1178 # skip comments before `then` token
1179 while not v
.current_token
isa TKwthen do v
.skip
1181 var n_else
= self.n_else
1185 if n_then
!= null then v
.visit n_then
1188 n_else
.force_inline
= true
1193 else if n_then
== null then
1197 v
.skip_to last_token
.last_real_token_in_line
1203 if n_then
!= null then
1204 if n_then
isa ABlockExpr then
1205 n_then
.force_block
= true
1215 while not v
.current_token
isa TKwelse do
1216 v
.consume v
.current_token
.text
1223 if n_else
isa AIfExpr then
1224 n_else
.force_block
= true
1232 if n_else
isa ABlockExpr then
1233 n_else
.force_block
= true
1241 if last_token
isa TKwend then
1242 v
.catch_up last_token
1253 if last_token
.location
>= v
.current_token
.location
then v
.catch_up last_token
1257 if v
.current_token
isa TKwend then v
.skip
1261 assert v
.indent
== before
1264 redef fun is_inlinable
do
1265 if not super then return false
1266 if n_then
!= null and not n_then
.is_inlinable
then return false
1267 var n_else
= self.n_else
1268 if (n_else
isa ABlockExpr and not n_else
.n_expr
.is_empty
) or
1269 (not n_else
isa ABlockExpr and n_else
!= null) then
1272 if not collect_comments
.is_empty
then return false
1276 # Does this `if` statement contains a `else` part?
1277 private fun has_else
(v
: PrettyPrinterVisitor): Bool do
1279 if n_else
== null then return false
1280 var n_kwelse
= collect_kwelse
1281 if n_kwelse
== null then return false
1283 if n_else
isa ABlockExpr then
1284 var comments
: Array[TComment]
1286 if n_then
== null then
1287 comments
= v
.collect_comments
(n_expr
.last_token
, n_else
.last_token
)
1289 comments
= v
.collect_comments
(n_then
.last_token
, n_else
.last_token
)
1292 if not comments
.is_empty
then return true
1293 return not n_else
.n_expr
.is_empty
1299 # Lookup for `else` token in `self`.
1300 private fun collect_kwelse
: nullable TKwelse do
1301 var token
= first_token
1303 while token
!= last_token
do
1304 if token
isa TKwelse then return token
1305 token
= token
.next_token
1312 # Used to factorize work on loops.
1313 private class ALoopHelper
1316 fun loop_block
: nullable ANode is abstract
1317 fun loop_label
: nullable ANode is abstract
1319 fun visit_loop_block
(v
: PrettyPrinterVisitor) do
1320 var n_block
= loop_block
1325 if n_block
isa ABlockExpr then
1326 n_block
.force_block
= true
1328 v
.catch_up n_block
.n_kwend
1331 v
.visit n_block
.n_kwend
1341 if loop_label
!= null then
1347 fun visit_loop_inline
(v
: PrettyPrinterVisitor) do
1348 var n_block
= loop_block
1351 if n_block
isa ABlockExpr then
1352 if n_block
.n_expr
.is_empty
then
1353 v
.visit n_block
.n_kwend
1355 v
.visit n_block
.n_expr
.first
1356 v
.current_token
= n_block
.n_kwend
1361 if v
.current_token
isa TKwend then v
.skip
1364 if loop_label
!= null then
1370 redef fun is_inlinable
do
1371 var n_block
= loop_block
1372 if not super then return false
1373 if n_block
isa ABlockExpr and not n_block
.is_inlinable
then return false
1374 if not collect_comments
.is_empty
then return false
1379 redef class ALoopExpr
1382 redef fun loop_block
do return n_block
1383 redef fun loop_label
do return n_label
1385 redef fun accept_pretty_printer
(v
) do
1386 var can_inline
= v
.can_inline
(self)
1388 if can_inline
then visit_loop_inline v
else visit_loop_block v
1392 redef class AWhileExpr
1395 redef fun loop_block
do return n_block
1396 redef fun loop_label
do return n_label
1398 redef fun accept_pretty_printer
(v
) do
1399 var can_inline
= v
.can_inline
(self)
1405 if can_inline
then visit_loop_inline v
else visit_loop_block v
1412 redef fun loop_block
do return n_block
1413 redef fun loop_label
do return n_label
1415 redef fun accept_pretty_printer
(v
) do
1416 var can_inline
= v
.can_inline
(self)
1418 if can_inline
then visit_loop_inline v
else visit_loop_block v
1422 redef class AForExpr
1425 redef fun loop_block
do return n_block
1426 redef fun loop_label
do return n_label
1428 redef fun accept_pretty_printer
(v
) do
1429 var can_inline
= v
.can_inline
(self)
1433 for n_id
in n_ids
do
1435 if n_id
!= n_ids
.last
then v
.add
", "
1444 if can_inline
then visit_loop_inline v
else visit_loop_block v
1448 redef class ABreakExpr
1449 redef fun accept_pretty_printer
(v
) do
1452 if n_expr
!= null then
1457 if n_label
!= null then
1463 redef fun is_inlinable
do return true
1466 redef class AContinueExpr
1467 redef fun accept_pretty_printer
(v
) do
1468 v
.visit n_kwcontinue
1470 if n_expr
!= null then
1475 if n_label
!= null then
1481 redef fun is_inlinable
do return true
1486 redef class ASendExpr
1487 redef fun is_inlinable
do return true
1490 redef class ACallExpr
1491 redef fun accept_pretty_printer
(v
) do
1492 var can_inline
= v
.can_inline
(self)
1495 if not n_expr
isa AImplicitSelfExpr and not can_inline
then
1502 if not n_args
.n_exprs
.is_empty
then
1503 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1505 if v
.current_token
isa TOpar then v
.skip
1506 v
.visit n_args
.n_exprs
.first
1507 if v
.current_token
isa TCpar then v
.skip
1509 if v
.current_token
isa TOpar then
1515 v
.visit_list n_args
.n_exprs
1516 if v
.current_token
isa TCpar then v
.consume
")"
1521 # Is the call alone on its line?
1522 fun is_stmt
: Bool do return parent
isa ABlockExpr
1525 redef class ACallAssignExpr
1526 redef fun accept_pretty_printer
(v
) do
1530 if not n_args
.n_exprs
.is_empty
then
1532 v
.visit_list n_args
.n_exprs
1543 redef class ACallReassignExpr
1544 redef fun accept_pretty_printer
(v
) do
1548 if not n_args
.n_exprs
.is_empty
then
1550 v
.visit_list n_args
.n_exprs
1561 redef class ABraExpr
1562 redef fun accept_pretty_printer
(v
) do
1565 if not n_args
.n_exprs
.is_empty
then
1567 v
.visit_list n_args
.n_exprs
1573 redef class ABraAssignExpr
1574 redef fun accept_pretty_printer
(v
) do
1577 if not n_args
.n_exprs
.is_empty
then
1579 v
.visit_list n_args
.n_exprs
1590 redef class ABraReassignExpr
1591 redef fun accept_pretty_printer
(v
) do
1594 if not n_args
.n_exprs
.is_empty
then
1596 v
.visit_list n_args
.n_exprs
1607 redef class AAssignMethid
1608 redef fun accept_pretty_printer
(v
) do
1614 redef class ABraMethid
1615 redef fun accept_pretty_printer
(v
) do
1621 redef class ABraassignMethid
1622 redef fun accept_pretty_printer
(v
) do
1629 redef class AInitExpr
1630 redef fun accept_pretty_printer
(v
) do
1631 if not n_expr
isa AImplicitSelfExpr then
1638 if not n_args
.n_exprs
.is_empty
then
1640 v
.visit_list n_args
.n_exprs
1646 redef class ANewExpr
1647 redef fun accept_pretty_printer
(v
) do
1648 var can_inline
= v
.can_inline
(self)
1653 if n_id
!= null then
1656 if not can_inline
then
1666 if not n_args
.n_exprs
.is_empty
then
1668 v
.visit_list n_args
.n_exprs
1673 redef fun is_inlinable
do return true
1678 redef class AAttrExpr
1679 redef fun accept_pretty_printer
(v
) do
1684 redef fun is_inlinable
do return true
1687 redef class AAttrAssignExpr
1688 redef fun accept_pretty_printer
(v
) do
1698 redef class AAttrReassignExpr
1699 redef fun accept_pretty_printer
(v
) do
1711 redef class AVardeclExpr
1712 redef fun accept_pretty_printer
(v
) do
1717 if n_type
!= null then
1723 if n_expr
!= null then
1731 redef fun is_inlinable
do return true
1734 redef class AVarAssignExpr
1735 redef fun accept_pretty_printer
(v
) do
1744 redef class AAssertExpr
1745 redef fun accept_pretty_printer
(v
) do
1746 var can_inline
= v
.can_inline
(self)
1749 if n_id
!= null then
1757 var n_else
= self.n_else
1759 if n_else
!= null then
1770 if n_else
isa ABlockExpr then
1771 n_else
.force_block
= true
1775 v
.visit n_else
.n_kwend
1788 redef fun is_inlinable
do
1789 if not super then return false
1790 if n_else
!= null and not n_else
.is_inlinable
then return false
1795 redef class AReturnExpr
1796 redef fun accept_pretty_printer
(v
) do
1799 if n_expr
!= null then
1806 redef class ASuperExpr
1807 redef fun accept_pretty_printer
(v
) do
1810 if not n_args
.n_exprs
.is_empty
then
1811 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1813 if v
.current_token
isa TOpar then v
.skip
1814 v
.visit n_args
.n_exprs
.first
1815 if v
.current_token
isa TCpar then v
.skip
1817 if v
.current_token
isa TOpar then
1823 v
.visit_list n_args
.n_exprs
1824 if v
.current_token
isa TCpar then v
.consume
")"
1829 # Is the call alone on its line?
1830 fun is_stmt
: Bool do return self.first_token
.is_starting_line
1832 redef fun is_inlinable
do return true
1835 redef class AOnceExpr
1836 redef fun accept_pretty_printer
(v
) do
1842 redef fun is_inlinable
do return true
1845 redef class AAbortExpr
1846 redef fun accept_pretty_printer
(v
) do v
.visit n_kwabort
1847 redef fun is_inlinable
do return true
1850 redef class ANotExpr
1851 redef fun accept_pretty_printer
(v
) do
1858 redef class AAsCastExpr
1859 redef fun accept_pretty_printer
(v
) do
1869 redef class AAsNotnullExpr
1870 redef fun accept_pretty_printer
(v
) do
1884 # Used to factorize work on Or, And, Implies and Binop expressions.
1885 private class ABinOpHelper
1888 fun bin_expr1
: AExpr is abstract
1889 fun bin_expr2
: AExpr is abstract
1892 fun bin_op
: String is abstract
1894 redef fun accept_pretty_printer
(v
) do
1895 var can_inline
= v
.can_inline
(self)
1897 if not can_inline
then
1898 if (self isa ABinopExpr and bin_expr1
isa ABinopExpr) or
1899 (self isa AAndExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr)) or
1900 (self isa AOrExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr))
1902 bin_expr1
.force_block
= true
1923 redef class AAndExpr
1926 redef fun bin_expr1
do return n_expr
1927 redef fun bin_expr2
do return n_expr2
1928 redef fun bin_op
do return "and"
1934 redef fun bin_expr1
do return n_expr
1935 redef fun bin_expr2
do return n_expr2
1936 redef fun bin_op
do return "or"
1939 redef class AImpliesExpr
1942 redef fun bin_expr1
do return n_expr
1943 redef fun bin_expr2
do return n_expr2
1944 redef fun bin_op
do return "implies"
1947 redef class ABinopExpr
1950 redef fun bin_expr1
do return n_expr
1951 redef fun bin_expr2
do return n_expr2
1955 redef fun bin_op
do return "=="
1959 redef fun bin_op
do return ">="
1963 redef fun bin_op
do return ">>"
1967 redef fun bin_op
do return ">"
1971 redef fun bin_op
do return "<="
1975 redef fun bin_op
do return "<<"
1979 redef fun bin_op
do return "<"
1982 redef class AMinusExpr
1983 redef fun bin_op
do return "-"
1987 redef fun bin_op
do return "!="
1990 redef class APercentExpr
1991 redef fun bin_op
do return "%"
1994 redef class APlusExpr
1995 redef fun bin_op
do return "+"
1998 redef class ASlashExpr
1999 redef fun bin_op
do return "/"
2002 redef class AStarExpr
2003 redef fun bin_op
do return "*"
2006 redef class AStarstarExpr
2007 redef fun bin_op
do return "**"
2010 redef class AStarshipExpr
2011 redef fun bin_op
do return "<=>"
2014 redef class AIsaExpr
2015 redef fun accept_pretty_printer
(v
) do
2024 redef class AOrElseExpr
2025 redef fun accept_pretty_printer
(v
) do
2035 redef fun is_inlinable
do return true
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
2119 v
.current_token
= n_string
.next_token
2124 redef class ASuperstringExpr
2125 redef fun accept_pretty_printer
(v
) do
2126 for n_expr
in n_exprs
do
2127 if not v
.break_strings
then
2128 n_expr
.force_inline
= true
2134 redef fun must_be_inline
do
2135 if super then return true
2137 if not n_exprs
.is_empty
then
2138 var first
= n_exprs
.first
2139 return first
isa AStringFormExpr and first
.n_string
.text
.has_prefix
("\"\
"\"")