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.
17 # See `nitpretty` tool for more documentation.
25 # The `PrettyPrinterVisitor` is used to visit a node and pretty print it.
27 # The main method here is `visit` that performs the pretty printing of a `ANode`.
29 # Because some tokens like `TComment` are not stored in the AST,
30 # we visit the AST like traditionnal visitor and also maintain a
31 # pointer to the `current_token` (actually the next one to be printed).
33 # Visited productions are in charges to move the token pointer using methods such as:
35 # * `consume`: print `current_token` and move to the next one
36 # * `skip`: move to the next token without printing the current one
37 # * `skip_to`: move to a specified token skipping all the tokens before
38 # * `catch_up`: consume all the tokens between `current_token` and a specified token
39 # * `finish_line`: consume all the tokens between `current_token` and the end of line
40 class PrettyPrinterVisitor
42 fun pretty
(n
: ANode): Template do
47 current_token
= n
.first_token
49 else if n
isa Token then
52 while p
!= null and not p
isa Prod do
56 current_token
= p
.first_token
60 return tpl
.as(not null)
63 # Pretty print the whole `nmodule` with comments before and after.
64 fun pretty_nmodule
(nmodule
: AModule): Template do
66 nmodule
.parentize_tokens
67 current_token
= nmodule
.location
.file
.first_token
69 catch_up nmodule
.location
.file
.last_token
71 return tpl
.as(not null)
74 # Prepare `self` for a new visit.
84 # Visit `n` if not null.
85 fun visit
(n
: nullable ANode) do
86 if n
== null then return
87 n
.accept_pretty_printer
self
90 # Visit a list of `Anode`.
91 fun visit_list
(n
: nullable ANodes[ANode]) do
92 if n
== null then return
93 n
.accept_pretty_printer
self
96 # Is the node inlinable and can fit on the line.
97 fun can_inline
(n
: nullable ANode): Bool do
98 if n
== null then return true
99 if n
.must_be_inline
then return true
100 if n
.must_be_block
then return false
102 if n
.collect_length
+ current_length
> max_size
then return false
103 # check block is inlinable
104 return n
.is_inlinable
107 # Collect all `TComment` between `from` and `to`.
108 fun collect_comments
(from
: nullable ANode, to
: nullable ANode): Array[TComment] do
109 var res
= new Array[TComment]
110 if from
isa Prod then from
= from
.first_token
111 if to
isa Prod then to
= to
.first_token
112 if from
== null or to
== null then return res
115 if from
isa TComment then res
.add from
116 from
= from
.as(Token).next_token
122 # Token under cursor.
124 # This is the next token to visit.
125 var current_token
: nullable Token = null
127 # Skip the `current_token`.
128 fun skip
do current_token
= current_token
.next_token
130 # Skip `current_token` until the end of line.
131 fun skip_line
do current_token
= current_token
.last_real_token_in_line
133 # Skip `current_token` until `target` is reached.
134 fun skip_to
(target
: nullable Token) do
135 if target
== null then return
136 while current_token
!= target
do skip
139 # Visit `current_token`.
140 fun consume
(token
: String) do
141 assert current_token
.text
== token
145 # Is there token to visit between `current_token` and `target`?
146 fun need_catch_up
(target
: nullable Token): Bool do
147 if target
== null then return false
148 return current_token
!= target
151 # Visit all tokens between `current_token` and `target`.
152 fun catch_up
(target
: nullable ANode) do
153 if target
== null then return
154 if current_token
== null then return
156 if target
isa Token then
158 else if target
isa Prod then
159 token
= target
.first_token
.as(not null)
163 assert current_token
.location
<= token
.location
164 while current_token
!= token
do visit current_token
167 # Visit all tokens between `current_token` and the end of line.
169 if current_token
isa TComment then
174 while current_token
isa TEol do skip
177 # The template under construction.
178 private var tpl
: nullable Template = null
180 # Current indent level.
183 # Size of a tabulation in spaces.
189 # Length of the current line.
190 var current_length
= 0
192 # Length of the previous line.
193 var previous_length
= 0
195 # Is the last line a blank line?
196 fun last_line_is_blank
: Bool do return previous_length
== 0
198 # Add `t` to current template.
199 fun add
(t
: String) do
200 if t
.is_empty
then return
201 while wait_addn
> 0 do
206 current_length
+= t
.length
211 if current_length
== 0 and last_line_is_blank
then return
212 previous_length
= current_length
217 # End of line chars are stored until another char is added.
218 # This avoid empty files with only a '`\n`'.
219 private var wait_addn
= 0
221 # Add `'\t' * indent`.
222 fun addt
do add
"\t" * indent
227 # Visit explicit receiver, implicit self will be ignored.
228 fun visit_recv
(n_expr
: AExpr) do
229 if not n_expr
isa AImplicitSelfExpr then
236 # Base framework redefs
238 redef class ANodes[E
]
239 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) do
241 var e_can_inline
= v
.can_inline
(e
)
244 if not e_can_inline
then
260 # Start visit of `self` using a `PrettyPrinterVisitor`
261 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) is abstract
263 # Collect the length (in `Char`) of the node.
264 private fun collect_length
: Int is abstract
266 # Is `self` printable in one line?
267 private fun is_inlinable
: Bool do return true
269 # Force `self` to be rendered as a block.
270 private var force_block
= false
272 # Does `self` have to be rendered as a block?
273 private fun must_be_block
: Bool do return force_block
275 # Force `self` to be rendered as a line.
276 private var force_inline
= false
278 # Does `self` have be rendered as a line?
279 private fun must_be_inline
: Bool do
280 if parent
!= null and parent
.must_be_inline
then return true
284 # Does `self` was written in one line before transformation?
285 private fun was_inline
: Bool is abstract
289 redef fun accept_pretty_printer
(v
) do
291 v
.current_token
= next_token
294 redef fun collect_length
do return text
.length
295 redef fun is_inlinable
do return true
296 redef fun was_inline
do return true
300 redef fun accept_pretty_printer
(v
) do v
.visit first_token
302 # The token where the production really start (skipping ADoc).
303 private fun start_token
: nullable Token do return first_token
305 # Collect all `TComment` contained in the production
306 # (between `start_token` and `end_token`).
307 private fun collect_comments
: Array[TComment] do
308 var res
= new Array[TComment]
309 if start_token
== null or last_token
== null then return res
310 var token
= start_token
312 while token
!= last_token
do
313 if token
isa TComment then res
.add token
314 token
= token
.next_token
320 redef fun collect_length
do
322 if start_token
== null or last_token
== null then return res
323 var token
= start_token
325 while token
!= last_token
do
326 res
+= token
.text
.length
327 token
= token
.next_token
330 res
+= token
.text
.length
334 redef fun was_inline
do
335 return first_token
.location
.line_start
== last_token
.location
.line_end
342 redef fun accept_pretty_printer
(v
) do
353 if is_last_in_group
then v
.addn
367 if next_token
isa TComment and is_first_in_group
then v
.addn
371 var prev_token
= self.prev_token
372 if prev_token
isa TComment and prev_token
.is_inline
and is_last_in_group
then v
.addn
379 # Is `self` part of an `ADoc`?
380 private fun is_adoc
: Bool do return parent
isa ADoc and parent
.parent
!= null
382 # Is `self` part of a licence?
383 private fun is_licence
: Bool do
384 var prev_token
= self.prev_token
386 if prev_token
== null then
388 else if prev_token
isa TComment then
389 return prev_token
.is_licence
395 # Is `self` starts and ends its line?
396 private fun is_inline
: Bool do
397 return self == first_real_token_in_line
and self == last_real_token_in_line
400 # Is `self` an orphan line (blank before and after)?
401 private fun is_orphan
: Bool do
402 return prev_token
isa TEol and
403 (prev_token
.prev_token
isa TEol or prev_token
.prev_token
isa TComment) and
407 # Is `self` the first comment of a group of comment?
408 private fun is_first_in_group
: Bool do return not prev_token
isa TComment
410 # Is `self` the last comment of a group of comments?
411 private fun is_last_in_group
: Bool do return not next_token
isa TComment
415 redef fun accept_pretty_printer
(v
) do for comment
in n_comment
do v
.visit comment
416 redef fun is_inlinable
do return n_comment
.length
<= 1
421 redef class AAnnotations
422 redef fun accept_pretty_printer
(v
) do
426 if v
.can_inline
(self) then
428 for n_item
in n_items
do
430 if n_item
!= n_items
.last
then
435 else if n_items
.length
> 1 then
439 for n_item
in n_items
do
448 if not was_inline
and v
.current_token
isa TKwend then v
.skip
451 redef fun is_inlinable
do
452 if not super then return false
453 for annot
in n_items
do if not annot
.is_inlinable
then return false
458 redef class AAnnotation
459 redef fun accept_pretty_printer
(v
) do
461 if not n_args
.is_empty
then
462 if n_opar
== null then
473 redef class ATypeExpr
474 redef fun accept_pretty_printer
(v
) do v
.visit n_type
480 redef fun accept_pretty_printer
(v
) do
481 v
.catch_up start_token
484 if not n_imports
.is_empty
then
487 for n_import
in n_imports
do
493 if not n_extern_code_blocks
.is_empty
then
496 for n_extern_block
in n_extern_code_blocks
do
497 v
.catch_up n_extern_block
498 v
.visit n_extern_block
500 if n_extern_block
!= n_extern_code_blocks
.last
then v
.addn
503 if not n_classdefs
.is_empty
then v
.addn
506 if not n_classdefs
.is_empty
then
509 for n_classdef
in n_classdefs
do
510 v
.catch_up n_classdef
512 if n_classdef
!= n_classdefs
.last
then v
.addn
520 redef fun start_token
do
521 if n_moduledecl
!= null then return n_moduledecl
.first_token
522 if not n_imports
.is_empty
then return n_imports
.first
.first_token
523 if not n_classdefs
.is_empty
then return n_classdefs
.first
.first_token
527 redef fun is_inlinable
do return false
530 redef class AModuledecl
531 redef fun accept_pretty_printer
(v
) do
537 if n_annotations
!= null then
538 var annot_inline
= v
.can_inline
(n_annotations
)
539 v
.visit n_annotations
541 if not annot_inline
then
542 if v
.current_token
isa TKwend then
556 redef class AModuleName
557 redef fun accept_pretty_printer
(v
) do
558 for path
in n_path
do
567 redef class ANoImport
568 redef fun accept_pretty_printer
(v
) do
577 redef class AStdImport
578 redef fun accept_pretty_printer
(v
) do
579 if not n_visibility
isa APublicVisibility then
594 redef class AClassdef
595 redef fun accept_pretty_printer
(v
) do
596 for n_propdef
in n_propdefs
do
599 if n_propdef
.n_doc
!= null or not v
.can_inline
(n_propdef
) then
600 if n_propdef
!= n_propdefs
.first
then v
.addn
602 if n_propdef
!= n_propdefs
.last
then v
.addn
610 redef class AStdClassdef
611 redef fun accept_pretty_printer
(v
) do
613 var can_inline
= v
.can_inline
(self)
615 if not n_visibility
isa APublicVisibility then
620 if n_kwredef
!= null then
629 if not n_formaldefs
.is_empty
then
631 v
.visit_list n_formaldefs
635 if n_extern_code_block
!= null then
637 v
.visit n_extern_code_block
643 if not n_superclasses
.is_empty
then
644 for n_superclass
in n_superclasses
do
654 for n_superclass
in n_superclasses
do
655 v
.catch_up n_superclass
662 if not n_superclasses
.is_empty
and not n_propdefs
.is_empty
then
677 redef fun is_inlinable
do
678 if not super then return false
679 if not n_propdefs
.is_empty
then return false
680 if n_superclasses
.length
> 1 then return false
681 if not collect_comments
.is_empty
then return false
685 redef fun start_token
do
686 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
687 if n_kwredef
!= null then return n_kwredef
688 return n_classkind
.first_token
692 redef class AAbstractClasskind
693 redef fun accept_pretty_printer
(v
) do
700 redef class AExternClasskind
701 redef fun accept_pretty_printer
(v
) do
708 redef class AFormaldef
709 redef fun accept_pretty_printer
(v
) do
712 if n_type
!= null then
721 redef fun accept_pretty_printer
(v
) do
722 if n_kwnullable
!= null then
729 if not n_types
.is_empty
then
737 redef class ASuperclass
738 redef fun accept_pretty_printer
(v
) do
748 redef fun accept_pretty_printer
(v
) do
752 if not n_visibility
isa APublicVisibility then
757 if n_kwredef
!= null then
763 redef fun start_token
do
764 if n_doc
== null then return super
765 return n_doc
.last_token
.next_token
769 redef class AAttrPropdef
770 redef fun accept_pretty_printer
(v
) do
776 if n_type
!= null then
782 if n_expr
!= null then
789 if n_annotations
!= null then v
.visit n_annotations
794 redef fun first_token
do
795 if n_doc
!= null then return n_doc
.first_token
796 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
797 if n_kwredef
!= null then return n_kwredef
801 redef fun is_inlinable
do return true
804 redef class ATypePropdef
805 redef fun accept_pretty_printer
(v
) do
817 redef fun is_inlinable
do return true
820 redef class AMethPropdef
821 redef fun accept_pretty_printer
(v
) do
822 # TODO: Handle extern annotations
824 var before
= v
.indent
825 var can_inline
= v
.can_inline
(self)
827 if n_kwinit
!= null then v
.visit n_kwinit
828 if n_kwmeth
!= null then v
.visit n_kwmeth
829 if n_kwnew
!= null then v
.visit n_kwnew
831 if not n_methid
== null then
838 if n_annotations
!= null then
839 v
.visit n_annotations
844 if n_extern_calls
!= null or n_extern_code_block
!= null then
845 if n_annotations
!= null then v
.adds
846 if n_extern_calls
!= null then v
.visit n_extern_calls
847 if n_extern_code_block
!= null then v
.visit n_extern_code_block
850 var n_block
= self.n_block
852 if n_block
!= null then
853 while not v
.current_token
isa TKwdo do v
.skip
854 if n_annotations
!= null then
855 if v
.can_inline
(n_annotations
) then
866 if n_block
isa ABlockExpr then
867 if n_block
.n_expr
.is_empty
then
868 v
.visit n_block
.n_kwend
870 v
.visit n_block
.n_expr
.first
871 v
.current_token
= n_block
.n_kwend
876 if v
.current_token
isa TKwend then v
.skip
883 if n_block
isa ABlockExpr then
884 n_block
.force_block
= true
886 v
.catch_up n_block
.n_kwend
895 if n_block
isa ABlockExpr then
896 v
.visit n_block
.n_kwend
905 assert v
.indent
== before
909 # * block is empty or can be inlined
910 # * contains no comments
911 redef fun is_inlinable
do
912 if not super then return false
913 if n_annotations
!= null and not n_annotations
.is_inlinable
then return false
914 if n_block
!= null and not n_block
.is_inlinable
then return false
915 if n_extern_calls
!= null and not n_extern_calls
.is_inlinable
then return false
916 if n_extern_code_block
!= null and not n_extern_code_block
.is_inlinable
then return false
917 if not collect_comments
.is_empty
then return false
922 redef class AMainMethPropdef
923 redef fun accept_pretty_printer
(v
) do
929 redef class ASignature
930 redef fun accept_pretty_printer
(v
) do
931 if not n_params
.is_empty
then
933 v
.visit_list n_params
937 if n_type
!= null then
946 redef fun accept_pretty_printer
(v
) do
949 if n_type
!= null then
955 if n_dotdotdot
!= null then v
.visit n_dotdotdot
961 redef class AExternCalls
962 redef fun accept_pretty_printer
(v
) do
963 var can_inline
= v
.can_inline
(self)
968 v
.visit_list n_extern_calls
973 v
.visit_list n_extern_calls
980 redef class AFullPropExternCall
981 redef fun accept_pretty_printer
(v
) do
988 redef class ALocalPropExternCall
989 redef fun accept_pretty_printer
(v
) do v
.visit n_methid
992 redef class AInitPropExternCall
993 redef fun accept_pretty_printer
(v
) do v
.visit n_type
996 redef class ACastAsExternCall
997 redef fun accept_pretty_printer
(v
) do
1007 redef class AAsNullableExternCall
1008 redef fun accept_pretty_printer
(v
) do
1013 v
.visit n_kwnullable
1017 redef class AAsNotNullableExternCall
1018 redef fun accept_pretty_printer
(v
) do
1025 v
.visit n_kwnullable
1029 redef class AExternCodeBlock
1030 redef fun accept_pretty_printer
(v
) do
1031 if n_in_language
!= null then
1032 v
.visit n_in_language
1036 v
.visit n_extern_code_segment
1039 redef fun is_inlinable
do
1040 if not super then return false
1041 return n_extern_code_segment
.is_inlinable
1045 redef class AInLanguage
1046 redef fun accept_pretty_printer
(v
) do
1053 redef class TExternCodeSegment
1054 redef fun accept_pretty_printer
(v
) do
1055 var can_inline
= v
.can_inline
(self)
1060 var text
= text
.substring
(2, text
.length
- 4)
1061 var lines
= text
.r_trim
.split
("\n")
1063 if text
.is_empty
then
1068 if not lines
.first
.trim
.is_empty
then
1076 for line
in lines
do
1085 v
.current_token
= next_token
1089 redef fun is_inlinable
do
1090 if not super then return false
1091 return location
.line_start
== location
.line_end
1097 redef class ABlockExpr
1098 redef fun accept_pretty_printer
(v
) do
1099 var before
= v
.indent
1100 var can_inline
= v
.can_inline
(self)
1102 if can_inline
and not n_expr
.is_empty
then
1103 v
.visit n_expr
.first
1106 for nexpr
in n_expr
do
1107 var expr_inline
= v
.can_inline
(nexpr
)
1108 if not expr_inline
and nexpr
!= n_expr
.first
then v
.addn
1114 if not expr_inline
and nexpr
!= n_expr
.last
then v
.addn
1118 assert v
.indent
== before
1121 redef fun is_inlinable
do
1122 if not super then return false
1123 if not collect_comments
.is_empty
then return false
1125 if not n_expr
.is_empty
then
1126 if n_expr
.length
> 1 then return false
1127 if not n_expr
.first
.is_inlinable
then return false
1135 redef fun accept_pretty_printer
(v
) do
1136 var before
= v
.indent
1137 var can_inline
= v
.can_inline
(self)
1141 if v
.can_inline
(n_expr
) then
1150 # skip comments before `then` token
1151 while not v
.current_token
isa TKwthen do v
.skip
1153 var n_else
= self.n_else
1157 if n_then
!= null then v
.visit n_then
1160 n_else
.force_inline
= true
1165 else if n_then
== null then
1169 v
.skip_to last_token
.last_real_token_in_line
1175 if n_then
!= null then
1176 if n_then
isa ABlockExpr then
1177 n_then
.force_block
= true
1187 while not v
.current_token
isa TKwelse do
1188 v
.consume v
.current_token
.text
1195 if n_else
isa AIfExpr then
1196 n_else
.force_block
= true
1204 if n_else
isa ABlockExpr then
1205 n_else
.force_block
= true
1213 if last_token
isa TKwend then
1214 v
.catch_up last_token
1225 if last_token
.location
>= v
.current_token
.location
then v
.catch_up last_token
1229 if v
.current_token
isa TKwend then v
.skip
1233 assert v
.indent
== before
1236 redef fun is_inlinable
do
1237 if not super then return false
1238 if n_then
!= null and not n_then
.is_inlinable
then return false
1239 var n_else
= self.n_else
1240 if (n_else
isa ABlockExpr and not n_else
.n_expr
.is_empty
) or
1241 (not n_else
isa ABlockExpr and n_else
!= null) then
1244 if not collect_comments
.is_empty
then return false
1248 # Does this `if` statement contains a `else` part?
1249 private fun has_else
(v
: PrettyPrinterVisitor): Bool do
1251 if n_else
== null then return false
1252 var n_kwelse
= collect_kwelse
1253 if n_kwelse
== null then return false
1255 if n_else
isa ABlockExpr then
1256 var comments
: Array[TComment]
1258 if n_then
== null then
1259 comments
= v
.collect_comments
(n_expr
.last_token
, n_else
.last_token
)
1261 comments
= v
.collect_comments
(n_then
.last_token
, n_else
.last_token
)
1264 if not comments
.is_empty
then return true
1265 return not n_else
.n_expr
.is_empty
1271 # Lookup for `else` token in `self`.
1272 private fun collect_kwelse
: nullable TKwelse do
1273 var token
= first_token
1275 while token
!= last_token
do
1276 if token
isa TKwelse then return token
1277 token
= token
.next_token
1284 # Used to factorize work on loops.
1285 private class ALoopHelper
1288 fun loop_block
: nullable ANode is abstract
1289 fun loop_label
: nullable ANode is abstract
1291 fun visit_loop_block
(v
: PrettyPrinterVisitor) do
1292 var n_block
= loop_block
1297 if n_block
isa ABlockExpr then
1298 n_block
.force_block
= true
1300 v
.catch_up n_block
.n_kwend
1303 v
.visit n_block
.n_kwend
1313 if loop_label
!= null then
1319 fun visit_loop_inline
(v
: PrettyPrinterVisitor) do
1320 var n_block
= loop_block
1323 if n_block
isa ABlockExpr then
1324 if n_block
.n_expr
.is_empty
then
1325 v
.visit n_block
.n_kwend
1327 v
.visit n_block
.n_expr
.first
1328 v
.current_token
= n_block
.n_kwend
1333 if v
.current_token
isa TKwend then v
.skip
1336 if loop_label
!= null then
1342 redef fun is_inlinable
do
1343 var n_block
= loop_block
1344 if not super then return false
1345 if n_block
isa ABlockExpr and not n_block
.is_inlinable
then return false
1346 if not collect_comments
.is_empty
then return false
1351 redef class ALoopExpr
1354 redef fun loop_block
do return n_block
1355 redef fun loop_label
do return n_label
1357 redef fun accept_pretty_printer
(v
) do
1358 var can_inline
= v
.can_inline
(self)
1360 if can_inline
then visit_loop_inline v
else visit_loop_block v
1364 redef class AWhileExpr
1367 redef fun loop_block
do return n_block
1368 redef fun loop_label
do return n_label
1370 redef fun accept_pretty_printer
(v
) do
1371 var can_inline
= v
.can_inline
(self)
1377 if can_inline
then visit_loop_inline v
else visit_loop_block v
1384 redef fun loop_block
do return n_block
1385 redef fun loop_label
do return n_label
1387 redef fun accept_pretty_printer
(v
) do
1388 var can_inline
= v
.can_inline
(self)
1390 if can_inline
then visit_loop_inline v
else visit_loop_block v
1394 redef class AForExpr
1397 redef fun loop_block
do return n_block
1398 redef fun loop_label
do return n_label
1400 redef fun accept_pretty_printer
(v
) do
1401 var can_inline
= v
.can_inline
(self)
1405 for n_id
in n_ids
do
1407 if n_id
!= n_ids
.last
then v
.add
", "
1416 if can_inline
then visit_loop_inline v
else visit_loop_block v
1420 redef class ABreakExpr
1421 redef fun accept_pretty_printer
(v
) do
1424 if n_expr
!= null then
1429 if n_label
!= null then
1435 redef fun is_inlinable
do return true
1438 redef class AContinueExpr
1439 redef fun accept_pretty_printer
(v
) do
1440 v
.visit n_kwcontinue
1442 if n_expr
!= null then
1447 if n_label
!= null then
1453 redef fun is_inlinable
do return true
1458 redef class ASendExpr
1459 redef fun is_inlinable
do return true
1462 redef class ACallExpr
1463 redef fun accept_pretty_printer
(v
) do
1464 var can_inline
= v
.can_inline
(self)
1467 if not n_expr
isa AImplicitSelfExpr and not can_inline
then
1475 if not n_args
.n_exprs
.is_empty
then
1476 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1478 if v
.current_token
isa TOpar then v
.skip
1479 v
.visit n_args
.n_exprs
.first
1480 if v
.current_token
isa TCpar then v
.skip
1482 if v
.current_token
isa TOpar then
1488 v
.visit_list n_args
.n_exprs
1489 if v
.current_token
isa TCpar then v
.consume
")"
1494 # Is the call alone on its line?
1495 fun is_stmt
: Bool do return parent
isa ABlockExpr
1498 redef class ACallAssignExpr
1499 redef fun accept_pretty_printer
(v
) do
1503 if not n_args
.n_exprs
.is_empty
then
1505 v
.visit_list n_args
.n_exprs
1516 redef class ACallReassignExpr
1517 redef fun accept_pretty_printer
(v
) do
1521 if not n_args
.n_exprs
.is_empty
then
1523 v
.visit_list n_args
.n_exprs
1534 redef class ABraExpr
1535 redef fun accept_pretty_printer
(v
) do
1538 if not n_args
.n_exprs
.is_empty
then
1540 v
.visit_list n_args
.n_exprs
1546 redef class ABraAssignExpr
1547 redef fun accept_pretty_printer
(v
) do
1550 if not n_args
.n_exprs
.is_empty
then
1552 v
.visit_list n_args
.n_exprs
1563 redef class ABraReassignExpr
1564 redef fun accept_pretty_printer
(v
) do
1567 if not n_args
.n_exprs
.is_empty
then
1569 v
.visit_list n_args
.n_exprs
1580 redef class AAssignMethid
1581 redef fun accept_pretty_printer
(v
) do
1587 redef class ABraMethid
1588 redef fun accept_pretty_printer
(v
) do
1594 redef class ABraassignMethid
1595 redef fun accept_pretty_printer
(v
) do
1602 redef class AInitExpr
1603 redef fun accept_pretty_printer
(v
) do
1604 if not n_expr
isa AImplicitSelfExpr then
1611 if not n_args
.n_exprs
.is_empty
then
1613 v
.visit_list n_args
.n_exprs
1619 redef class ANewExpr
1620 redef fun accept_pretty_printer
(v
) do
1621 var can_inline
= v
.can_inline
(self)
1626 if n_id
!= null then
1629 if not can_inline
then
1638 if not n_args
.n_exprs
.is_empty
then
1640 v
.visit_list n_args
.n_exprs
1645 redef fun is_inlinable
do return true
1650 redef class AAttrExpr
1651 redef fun accept_pretty_printer
(v
) do
1656 redef fun is_inlinable
do return true
1659 redef class AAttrAssignExpr
1660 redef fun accept_pretty_printer
(v
) do
1670 redef class AAttrReassignExpr
1671 redef fun accept_pretty_printer
(v
) do
1683 redef class AVardeclExpr
1684 redef fun accept_pretty_printer
(v
) do
1689 if n_type
!= null then
1695 if n_expr
!= null then
1703 redef fun is_inlinable
do return true
1706 redef class AVarAssignExpr
1707 redef fun accept_pretty_printer
(v
) do
1716 redef class AAssertExpr
1717 redef fun accept_pretty_printer
(v
) do
1718 var can_inline
= v
.can_inline
(self)
1721 if n_id
!= null then
1729 var n_else
= self.n_else
1731 if n_else
!= null then
1741 if n_else
isa ABlockExpr then
1743 n_else
.force_block
= true
1747 v
.visit n_else
.n_kwend
1761 redef fun is_inlinable
do
1762 if not super then return false
1763 if n_else
!= null and not n_else
.is_inlinable
then return false
1768 redef class AReturnExpr
1769 redef fun accept_pretty_printer
(v
) do
1772 if n_expr
!= null then
1779 redef class ASuperExpr
1780 redef fun accept_pretty_printer
(v
) do
1783 if not n_args
.n_exprs
.is_empty
then
1784 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1786 if v
.current_token
isa TOpar then v
.skip
1787 v
.visit n_args
.n_exprs
.first
1788 if v
.current_token
isa TCpar then v
.skip
1790 if v
.current_token
isa TOpar then
1796 v
.visit_list n_args
.n_exprs
1797 if v
.current_token
isa TCpar then v
.consume
")"
1802 # Is the call alone on its line?
1803 fun is_stmt
: Bool do return self.first_token
.is_starting_line
1805 redef fun is_inlinable
do return true
1808 redef class AOnceExpr
1809 redef fun accept_pretty_printer
(v
) do
1815 redef fun is_inlinable
do return true
1818 redef class AAbortExpr
1819 redef fun accept_pretty_printer
(v
) do v
.visit n_kwabort
1820 redef fun is_inlinable
do return true
1823 redef class ANotExpr
1824 redef fun accept_pretty_printer
(v
) do
1831 redef class AAsCastExpr
1832 redef fun accept_pretty_printer
(v
) do
1842 redef class AAsNotnullExpr
1843 redef fun accept_pretty_printer
(v
) do
1857 # Used to factorize work on Or, And, Implies and Binop expressions.
1858 private class ABinOpHelper
1861 fun bin_expr1
: AExpr is abstract
1862 fun bin_expr2
: AExpr is abstract
1865 fun bin_op
: String is abstract
1867 redef fun accept_pretty_printer
(v
) do
1868 var can_inline
= v
.can_inline
(self)
1870 if not can_inline
then
1871 if (self isa ABinopExpr and bin_expr1
isa ABinopExpr) or
1872 (self isa AAndExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr)) or
1873 (self isa AOrExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr))
1875 bin_expr1
.force_block
= true
1895 redef class AAndExpr
1898 redef fun bin_expr1
do return n_expr
1899 redef fun bin_expr2
do return n_expr2
1900 redef fun bin_op
do return "and"
1906 redef fun bin_expr1
do return n_expr
1907 redef fun bin_expr2
do return n_expr2
1908 redef fun bin_op
do return "or"
1911 redef class AImpliesExpr
1914 redef fun bin_expr1
do return n_expr
1915 redef fun bin_expr2
do return n_expr2
1916 redef fun bin_op
do return "implies"
1919 redef class ABinopExpr
1922 redef fun bin_expr1
do return n_expr
1923 redef fun bin_expr2
do return n_expr2
1927 redef fun bin_op
do return "=="
1931 redef fun bin_op
do return ">="
1935 redef fun bin_op
do return ">>"
1939 redef fun bin_op
do return ">"
1943 redef fun bin_op
do return "<="
1947 redef fun bin_op
do return "<<"
1951 redef fun bin_op
do return "<"
1954 redef class AMinusExpr
1955 redef fun bin_op
do return "-"
1959 redef fun bin_op
do return "!="
1962 redef class APercentExpr
1963 redef fun bin_op
do return "%"
1966 redef class APlusExpr
1967 redef fun bin_op
do return "+"
1970 redef class ASlashExpr
1971 redef fun bin_op
do return "/"
1974 redef class AStarExpr
1975 redef fun bin_op
do return "*"
1978 redef class AStarstarExpr
1979 redef fun bin_op
do return "**"
1982 redef class AStarshipExpr
1983 redef fun bin_op
do return "<=>"
1986 redef class AIsaExpr
1987 redef fun accept_pretty_printer
(v
) do
1996 redef class AOrElseExpr
1997 redef fun accept_pretty_printer
(v
) do
2007 redef fun is_inlinable
do return true
2012 redef class AUminusExpr
2013 redef fun accept_pretty_printer
(v
) do
2019 redef class ANullExpr
2020 redef fun accept_pretty_printer
(v
) do v
.visit n_kwnull
2021 redef fun is_inlinable
do return true
2024 redef class AParExpr
2025 redef fun accept_pretty_printer
(v
) do
2032 redef class AArrayExpr
2033 redef fun accept_pretty_printer
(v
) do
2035 v
.visit_list n_exprs
.n_exprs
2040 redef class ACrangeExpr
2041 redef fun accept_pretty_printer
(v
) do
2050 redef class AOrangeExpr
2051 redef fun accept_pretty_printer
(v
) do
2062 redef class AStringFormExpr
2063 redef fun accept_pretty_printer
(v
) do
2064 var can_inline
= v
.can_inline
(self)
2069 var text
= n_string
.text
2072 while i
< text
.length
do
2075 if v
.current_length
>= v
.max_size
and i
<= text
.length
- 3 then
2087 v
.current_token
= n_string
.next_token
2092 redef class ASuperstringExpr
2093 redef fun accept_pretty_printer
(v
) do
2094 for n_expr
in n_exprs
do v
.visit n_expr
2097 redef fun must_be_inline
do
2098 if super then return true
2100 if not n_exprs
.is_empty
then
2101 var first
= n_exprs
.first
2102 return first
isa AStringFormExpr and first
.n_string
.text
.has_prefix
("\"\
"\"")