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 assert current_token
.location
<= token
.location
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
272 # Start visit of `self` using a `PrettyPrinterVisitor`
273 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) is abstract
275 # Collect the length (in `Char`) of the node.
276 private fun collect_length
: Int is abstract
278 # Is `self` printable in one line?
279 private fun is_inlinable
: Bool do return true
281 # Force `self` to be rendered as a block.
282 private var force_block
= false
284 # Does `self` have to be rendered as a block?
285 private fun must_be_block
: Bool do return force_block
287 # Force `self` to be rendered as a line.
288 private var force_inline
= false
290 # Does `self` have be rendered as a line?
291 private fun must_be_inline
: Bool do
292 if parent
!= null and parent
.must_be_inline
then return true
296 # Does `self` was written in one line before transformation?
297 private fun was_inline
: Bool is abstract
301 redef fun accept_pretty_printer
(v
) do
303 v
.current_token
= next_token
306 redef fun collect_length
do return text
.length
307 redef fun is_inlinable
do return true
308 redef fun was_inline
do return true
312 redef fun accept_pretty_printer
(v
) do v
.visit first_token
314 # The token where the production really start (skipping ADoc).
315 private fun start_token
: nullable Token do return first_token
317 # Collect all `TComment` contained in the production
318 # (between `start_token` and `end_token`).
319 private fun collect_comments
: Array[TComment] do
320 var res
= new Array[TComment]
321 if start_token
== null or last_token
== null then return res
322 var token
= start_token
324 while token
!= last_token
do
325 if token
isa TComment then res
.add token
326 token
= token
.next_token
332 redef fun collect_length
do
334 if start_token
== null or last_token
== null then return res
335 var token
= start_token
337 while token
!= last_token
do
338 res
+= token
.text
.length
339 token
= token
.next_token
342 res
+= token
.text
.length
346 redef fun was_inline
do
347 return first_token
.location
.line_start
== last_token
.location
.line_end
354 redef fun accept_pretty_printer
(v
) do
365 if is_last_in_group
then v
.addn
379 if next_token
isa TComment and is_first_in_group
then v
.addn
383 var prev_token
= self.prev_token
384 if prev_token
isa TComment and prev_token
.is_inline
and is_last_in_group
then v
.addn
391 # Is `self` part of an `ADoc`?
392 private fun is_adoc
: Bool do return parent
isa ADoc and parent
.parent
!= null
394 # Is `self` part of a licence?
395 private fun is_licence
: Bool do
396 var prev_token
= self.prev_token
398 if prev_token
== null then
400 else if prev_token
isa TComment then
401 return prev_token
.is_licence
407 # Is `self` starts and ends its line?
408 private fun is_inline
: Bool do
409 return self == first_real_token_in_line
and self == last_real_token_in_line
412 # Is `self` an orphan line (blank before and after)?
413 private fun is_orphan
: Bool do
414 return prev_token
isa TEol and
415 (prev_token
.prev_token
isa TEol or prev_token
.prev_token
isa TComment) and
419 # Is `self` the first comment of a group of comment?
420 private fun is_first_in_group
: Bool do return not prev_token
isa TComment
422 # Is `self` the last comment of a group of comments?
423 private fun is_last_in_group
: Bool do return not next_token
isa TComment
427 redef fun accept_pretty_printer
(v
) do for comment
in n_comment
do v
.visit comment
428 redef fun is_inlinable
do return n_comment
.length
<= 1
433 redef class AAnnotations
434 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
447 else if n_items
.length
> 1 then
451 for n_item
in n_items
do
460 if not was_inline
and v
.current_token
isa TKwend then v
.skip
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
473 if not n_args
.is_empty
then
474 if n_opar
== null then
485 redef class ATypeExpr
486 redef fun accept_pretty_printer
(v
) do v
.visit n_type
492 redef fun accept_pretty_printer
(v
) do
493 v
.catch_up start_token
496 if not n_imports
.is_empty
then
499 for n_import
in n_imports
do
505 if not n_extern_code_blocks
.is_empty
then
508 for n_extern_block
in n_extern_code_blocks
do
509 v
.catch_up n_extern_block
510 v
.visit n_extern_block
512 if n_extern_block
!= n_extern_code_blocks
.last
then v
.addn
515 if not n_classdefs
.is_empty
then v
.addn
518 if not n_classdefs
.is_empty
then
521 for n_classdef
in n_classdefs
do
522 v
.catch_up n_classdef
524 if n_classdef
!= n_classdefs
.last
then v
.addn
532 redef fun start_token
do
533 if n_moduledecl
!= null then return n_moduledecl
.first_token
534 if not n_imports
.is_empty
then return n_imports
.first
.first_token
535 if not n_classdefs
.is_empty
then return n_classdefs
.first
.first_token
539 redef fun is_inlinable
do return false
542 redef class AModuledecl
543 redef fun accept_pretty_printer
(v
) do
549 if n_annotations
!= null then
550 var annot_inline
= v
.can_inline
(n_annotations
)
551 v
.visit n_annotations
553 if not annot_inline
then
554 if v
.current_token
isa TKwend then
568 redef class AModuleName
569 redef fun accept_pretty_printer
(v
) do
570 for path
in n_path
do
579 redef class ANoImport
580 redef fun accept_pretty_printer
(v
) do
589 redef class AStdImport
590 redef fun accept_pretty_printer
(v
) do
591 if not n_visibility
isa APublicVisibility then
606 redef class AClassdef
607 redef fun accept_pretty_printer
(v
) do
608 for n_propdef
in n_propdefs
do
611 if n_propdef
.n_doc
!= null or not v
.can_inline
(n_propdef
) then
612 if n_propdef
!= n_propdefs
.first
then v
.addn
614 if n_propdef
!= n_propdefs
.last
then v
.addn
622 redef class AStdClassdef
623 redef fun accept_pretty_printer
(v
) do
625 var can_inline
= v
.can_inline
(self)
627 if not n_visibility
isa APublicVisibility then
632 if n_kwredef
!= null then
641 if not n_formaldefs
.is_empty
then
643 v
.visit_list n_formaldefs
647 if n_extern_code_block
!= null then
649 v
.visit n_extern_code_block
655 if not n_superclasses
.is_empty
then
656 for n_superclass
in n_superclasses
do
666 for n_superclass
in n_superclasses
do
667 v
.catch_up n_superclass
674 if not n_superclasses
.is_empty
and not n_propdefs
.is_empty
then
689 redef fun is_inlinable
do
690 if not super then return false
691 if not n_propdefs
.is_empty
then return false
692 if n_superclasses
.length
> 1 then return false
693 if not collect_comments
.is_empty
then return false
697 redef fun start_token
do
698 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
699 if n_kwredef
!= null then return n_kwredef
700 return n_classkind
.first_token
704 redef class AAbstractClasskind
705 redef fun accept_pretty_printer
(v
) do
712 redef class AExternClasskind
713 redef fun accept_pretty_printer
(v
) do
720 redef class AFormaldef
721 redef fun accept_pretty_printer
(v
) do
724 if n_type
!= null then
733 redef fun accept_pretty_printer
(v
) do
734 if n_kwnullable
!= null then
741 if not n_types
.is_empty
then
749 redef class ASuperclass
750 redef fun accept_pretty_printer
(v
) do
760 redef fun accept_pretty_printer
(v
) do
764 if not n_visibility
isa APublicVisibility then
769 if n_kwredef
!= null then
775 redef fun start_token
do
776 if n_doc
== null then return super
777 return n_doc
.last_token
.next_token
781 redef class AAttrPropdef
782 redef fun accept_pretty_printer
(v
) do
788 if n_type
!= null then
794 if n_expr
!= null then
801 if n_annotations
!= null then v
.visit n_annotations
806 redef fun first_token
do
807 if n_doc
!= null then return n_doc
.first_token
808 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
809 if n_kwredef
!= null then return n_kwredef
813 redef fun is_inlinable
do return true
816 redef class ATypePropdef
817 redef fun accept_pretty_printer
(v
) do
829 redef fun is_inlinable
do return true
832 redef class AMethPropdef
833 redef fun accept_pretty_printer
(v
) do
834 # TODO: Handle extern annotations
836 var before
= v
.indent
838 if n_kwinit
!= null then v
.visit n_kwinit
839 if n_kwmeth
!= null then v
.visit n_kwmeth
840 if n_kwnew
!= null then v
.visit n_kwnew
842 if not n_methid
== null then
849 if n_annotations
!= null then
850 v
.visit n_annotations
855 if n_extern_calls
!= null or n_extern_code_block
!= null then
856 if n_annotations
!= null then v
.adds
857 if n_extern_calls
!= null then v
.visit n_extern_calls
858 if n_extern_code_block
!= null then v
.visit n_extern_code_block
861 var n_block
= self.n_block
863 if n_block
!= null then
864 while not v
.current_token
isa TKwdo do v
.skip
865 if n_annotations
!= null then
866 if v
.can_inline
(n_annotations
) then
874 if v
.can_inline
(n_block
) then
877 if n_block
isa ABlockExpr then
878 if n_block
.n_expr
.is_empty
then
879 v
.visit n_block
.n_kwend
881 v
.visit n_block
.n_expr
.first
882 v
.current_token
= n_block
.n_kwend
887 if v
.current_token
isa TKwend then v
.skip
894 if n_block
isa ABlockExpr then
895 n_block
.force_block
= true
897 v
.catch_up n_block
.n_kwend
906 if n_block
isa ABlockExpr then
907 v
.visit n_block
.n_kwend
916 assert v
.indent
== before
920 # * block is empty or can be inlined
921 # * contains no comments
922 redef fun is_inlinable
do
923 if not super then return false
924 if n_annotations
!= null and not n_annotations
.is_inlinable
then return false
925 if n_block
!= null and not n_block
.is_inlinable
then return false
926 if n_extern_calls
!= null and not n_extern_calls
.is_inlinable
then return false
927 if n_extern_code_block
!= null and not n_extern_code_block
.is_inlinable
then return false
928 if not collect_comments
.is_empty
then return false
933 redef class AMainMethPropdef
934 redef fun accept_pretty_printer
(v
) do
940 redef class ASignature
941 redef fun accept_pretty_printer
(v
) do
942 if not n_params
.is_empty
then
944 v
.visit_list n_params
948 if n_type
!= null then
957 redef fun accept_pretty_printer
(v
) do
960 if n_type
!= null then
966 if n_dotdotdot
!= null then v
.visit n_dotdotdot
972 redef class AExternCalls
973 redef fun accept_pretty_printer
(v
) do
974 var can_inline
= v
.can_inline
(self)
979 v
.visit_list n_extern_calls
984 v
.visit_list n_extern_calls
991 redef class AFullPropExternCall
992 redef fun accept_pretty_printer
(v
) do
999 redef class ALocalPropExternCall
1000 redef fun accept_pretty_printer
(v
) do v
.visit n_methid
1003 redef class AInitPropExternCall
1004 redef fun accept_pretty_printer
(v
) do v
.visit n_type
1007 redef class ACastAsExternCall
1008 redef fun accept_pretty_printer
(v
) do
1018 redef class AAsNullableExternCall
1019 redef fun accept_pretty_printer
(v
) do
1024 v
.visit n_kwnullable
1028 redef class AAsNotNullableExternCall
1029 redef fun accept_pretty_printer
(v
) do
1036 v
.visit n_kwnullable
1040 redef class AExternCodeBlock
1041 redef fun accept_pretty_printer
(v
) do
1042 if n_in_language
!= null then
1043 v
.visit n_in_language
1047 v
.visit n_extern_code_segment
1050 redef fun is_inlinable
do
1051 if not super then return false
1052 return n_extern_code_segment
.is_inlinable
1056 redef class AInLanguage
1057 redef fun accept_pretty_printer
(v
) do
1064 redef class TExternCodeSegment
1065 redef fun accept_pretty_printer
(v
) do
1066 var can_inline
= v
.can_inline
(self)
1071 var text
= text
.substring
(2, text
.length
- 4)
1072 var lines
= text
.r_trim
.split
("\n")
1074 if text
.is_empty
then
1079 if not lines
.first
.trim
.is_empty
then
1087 for line
in lines
do
1096 v
.current_token
= next_token
1100 redef fun is_inlinable
do
1101 if not super then return false
1102 return location
.line_start
== location
.line_end
1108 redef class ABlockExpr
1109 redef fun accept_pretty_printer
(v
) do
1110 var before
= v
.indent
1111 var can_inline
= v
.can_inline
(self)
1113 if can_inline
and not n_expr
.is_empty
then
1114 v
.visit n_expr
.first
1117 for nexpr
in n_expr
do
1118 var expr_inline
= v
.can_inline
(nexpr
)
1119 if not expr_inline
and nexpr
!= n_expr
.first
then v
.addn
1125 if not expr_inline
and nexpr
!= n_expr
.last
then v
.addn
1129 assert v
.indent
== before
1132 redef fun is_inlinable
do
1133 if not super then return false
1134 if not collect_comments
.is_empty
then return false
1136 if not n_expr
.is_empty
then
1137 if n_expr
.length
> 1 then return false
1138 if not n_expr
.first
.is_inlinable
then return false
1146 redef fun accept_pretty_printer
(v
) do
1147 var before
= v
.indent
1148 var can_inline
= v
.can_inline
(self)
1152 if v
.can_inline
(n_expr
) then
1161 # skip comments before `then` token
1162 while not v
.current_token
isa TKwthen do v
.skip
1164 var n_else
= self.n_else
1168 if n_then
!= null then v
.visit n_then
1171 n_else
.force_inline
= true
1176 else if n_then
== null then
1180 v
.skip_to last_token
.last_real_token_in_line
1186 if n_then
!= null then
1187 if n_then
isa ABlockExpr then
1188 n_then
.force_block
= true
1198 while not v
.current_token
isa TKwelse do
1199 v
.consume v
.current_token
.text
1206 if n_else
isa AIfExpr then
1207 n_else
.force_block
= true
1215 if n_else
isa ABlockExpr then
1216 n_else
.force_block
= true
1224 if last_token
isa TKwend then
1225 v
.catch_up last_token
1236 if last_token
.location
>= v
.current_token
.location
then v
.catch_up last_token
1240 if v
.current_token
isa TKwend then v
.skip
1244 assert v
.indent
== before
1247 redef fun is_inlinable
do
1248 if not super then return false
1249 if n_then
!= null and not n_then
.is_inlinable
then return false
1250 var n_else
= self.n_else
1251 if (n_else
isa ABlockExpr and not n_else
.n_expr
.is_empty
) or
1252 (not n_else
isa ABlockExpr and n_else
!= null) then
1255 if not collect_comments
.is_empty
then return false
1259 # Does this `if` statement contains a `else` part?
1260 private fun has_else
(v
: PrettyPrinterVisitor): Bool do
1262 if n_else
== null then return false
1263 var n_kwelse
= collect_kwelse
1264 if n_kwelse
== null then return false
1266 if n_else
isa ABlockExpr then
1267 var comments
: Array[TComment]
1269 if n_then
== null then
1270 comments
= v
.collect_comments
(n_expr
.last_token
, n_else
.last_token
)
1272 comments
= v
.collect_comments
(n_then
.last_token
, n_else
.last_token
)
1275 if not comments
.is_empty
then return true
1276 return not n_else
.n_expr
.is_empty
1282 # Lookup for `else` token in `self`.
1283 private fun collect_kwelse
: nullable TKwelse do
1284 var token
= first_token
1286 while token
!= last_token
do
1287 if token
isa TKwelse then return token
1288 token
= token
.next_token
1295 # Used to factorize work on loops.
1296 private class ALoopHelper
1299 fun loop_block
: nullable ANode is abstract
1300 fun loop_label
: nullable ANode is abstract
1302 fun visit_loop_block
(v
: PrettyPrinterVisitor) do
1303 var n_block
= loop_block
1308 if n_block
isa ABlockExpr then
1309 n_block
.force_block
= true
1311 v
.catch_up n_block
.n_kwend
1314 v
.visit n_block
.n_kwend
1324 if loop_label
!= null then
1330 fun visit_loop_inline
(v
: PrettyPrinterVisitor) do
1331 var n_block
= loop_block
1334 if n_block
isa ABlockExpr then
1335 if n_block
.n_expr
.is_empty
then
1336 v
.visit n_block
.n_kwend
1338 v
.visit n_block
.n_expr
.first
1339 v
.current_token
= n_block
.n_kwend
1344 if v
.current_token
isa TKwend then v
.skip
1347 if loop_label
!= null then
1353 redef fun is_inlinable
do
1354 var n_block
= loop_block
1355 if not super then return false
1356 if n_block
isa ABlockExpr and not n_block
.is_inlinable
then return false
1357 if not collect_comments
.is_empty
then return false
1362 redef class ALoopExpr
1365 redef fun loop_block
do return n_block
1366 redef fun loop_label
do return n_label
1368 redef fun accept_pretty_printer
(v
) do
1369 var can_inline
= v
.can_inline
(self)
1371 if can_inline
then visit_loop_inline v
else visit_loop_block v
1375 redef class AWhileExpr
1378 redef fun loop_block
do return n_block
1379 redef fun loop_label
do return n_label
1381 redef fun accept_pretty_printer
(v
) do
1382 var can_inline
= v
.can_inline
(self)
1388 if can_inline
then visit_loop_inline v
else visit_loop_block v
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)
1401 if can_inline
then visit_loop_inline v
else visit_loop_block v
1405 redef class AForExpr
1408 redef fun loop_block
do return n_block
1409 redef fun loop_label
do return n_label
1411 redef fun accept_pretty_printer
(v
) do
1412 var can_inline
= v
.can_inline
(self)
1416 for n_id
in n_ids
do
1418 if n_id
!= n_ids
.last
then v
.add
", "
1427 if can_inline
then visit_loop_inline v
else visit_loop_block v
1431 redef class ABreakExpr
1432 redef fun accept_pretty_printer
(v
) do
1435 if n_expr
!= null then
1440 if n_label
!= null then
1446 redef fun is_inlinable
do return true
1449 redef class AContinueExpr
1450 redef fun accept_pretty_printer
(v
) do
1451 v
.visit n_kwcontinue
1453 if n_expr
!= null then
1458 if n_label
!= null then
1464 redef fun is_inlinable
do return true
1469 redef class ASendExpr
1470 redef fun is_inlinable
do return true
1473 redef class ACallExpr
1474 redef fun accept_pretty_printer
(v
) do
1475 var can_inline
= v
.can_inline
(self)
1478 if not n_expr
isa AImplicitSelfExpr and not can_inline
then
1486 if not n_args
.n_exprs
.is_empty
then
1487 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1489 if v
.current_token
isa TOpar then v
.skip
1490 v
.visit n_args
.n_exprs
.first
1491 if v
.current_token
isa TCpar then v
.skip
1493 if v
.current_token
isa TOpar then
1499 v
.visit_list n_args
.n_exprs
1500 if v
.current_token
isa TCpar then v
.consume
")"
1505 # Is the call alone on its line?
1506 fun is_stmt
: Bool do return parent
isa ABlockExpr
1509 redef class ACallAssignExpr
1510 redef fun accept_pretty_printer
(v
) do
1514 if not n_args
.n_exprs
.is_empty
then
1516 v
.visit_list n_args
.n_exprs
1527 redef class ACallReassignExpr
1528 redef fun accept_pretty_printer
(v
) do
1532 if not n_args
.n_exprs
.is_empty
then
1534 v
.visit_list n_args
.n_exprs
1545 redef class ABraExpr
1546 redef fun accept_pretty_printer
(v
) do
1549 if not n_args
.n_exprs
.is_empty
then
1551 v
.visit_list n_args
.n_exprs
1557 redef class ABraAssignExpr
1558 redef fun accept_pretty_printer
(v
) do
1561 if not n_args
.n_exprs
.is_empty
then
1563 v
.visit_list n_args
.n_exprs
1574 redef class ABraReassignExpr
1575 redef fun accept_pretty_printer
(v
) do
1578 if not n_args
.n_exprs
.is_empty
then
1580 v
.visit_list n_args
.n_exprs
1591 redef class AAssignMethid
1592 redef fun accept_pretty_printer
(v
) do
1598 redef class ABraMethid
1599 redef fun accept_pretty_printer
(v
) do
1605 redef class ABraassignMethid
1606 redef fun accept_pretty_printer
(v
) do
1613 redef class AInitExpr
1614 redef fun accept_pretty_printer
(v
) do
1615 if not n_expr
isa AImplicitSelfExpr then
1622 if not n_args
.n_exprs
.is_empty
then
1624 v
.visit_list n_args
.n_exprs
1630 redef class ANewExpr
1631 redef fun accept_pretty_printer
(v
) do
1632 var can_inline
= v
.can_inline
(self)
1637 if n_id
!= null then
1640 if not can_inline
then
1649 if not n_args
.n_exprs
.is_empty
then
1651 v
.visit_list n_args
.n_exprs
1656 redef fun is_inlinable
do return true
1661 redef class AAttrExpr
1662 redef fun accept_pretty_printer
(v
) do
1667 redef fun is_inlinable
do return true
1670 redef class AAttrAssignExpr
1671 redef fun accept_pretty_printer
(v
) do
1681 redef class AAttrReassignExpr
1682 redef fun accept_pretty_printer
(v
) do
1694 redef class AVardeclExpr
1695 redef fun accept_pretty_printer
(v
) do
1700 if n_type
!= null then
1706 if n_expr
!= null then
1714 redef fun is_inlinable
do return true
1717 redef class AVarAssignExpr
1718 redef fun accept_pretty_printer
(v
) do
1727 redef class AAssertExpr
1728 redef fun accept_pretty_printer
(v
) do
1729 var can_inline
= v
.can_inline
(self)
1732 if n_id
!= null then
1740 var n_else
= self.n_else
1742 if n_else
!= null then
1752 if n_else
isa ABlockExpr then
1754 n_else
.force_block
= true
1758 v
.visit n_else
.n_kwend
1772 redef fun is_inlinable
do
1773 if not super then return false
1774 if n_else
!= null and not n_else
.is_inlinable
then return false
1779 redef class AReturnExpr
1780 redef fun accept_pretty_printer
(v
) do
1783 if n_expr
!= null then
1790 redef class ASuperExpr
1791 redef fun accept_pretty_printer
(v
) do
1794 if not n_args
.n_exprs
.is_empty
then
1795 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1797 if v
.current_token
isa TOpar then v
.skip
1798 v
.visit n_args
.n_exprs
.first
1799 if v
.current_token
isa TCpar then v
.skip
1801 if v
.current_token
isa TOpar then
1807 v
.visit_list n_args
.n_exprs
1808 if v
.current_token
isa TCpar then v
.consume
")"
1813 # Is the call alone on its line?
1814 fun is_stmt
: Bool do return self.first_token
.is_starting_line
1816 redef fun is_inlinable
do return true
1819 redef class AOnceExpr
1820 redef fun accept_pretty_printer
(v
) do
1826 redef fun is_inlinable
do return true
1829 redef class AAbortExpr
1830 redef fun accept_pretty_printer
(v
) do v
.visit n_kwabort
1831 redef fun is_inlinable
do return true
1834 redef class ANotExpr
1835 redef fun accept_pretty_printer
(v
) do
1842 redef class AAsCastExpr
1843 redef fun accept_pretty_printer
(v
) do
1853 redef class AAsNotnullExpr
1854 redef fun accept_pretty_printer
(v
) do
1868 # Used to factorize work on Or, And, Implies and Binop expressions.
1869 private class ABinOpHelper
1872 fun bin_expr1
: AExpr is abstract
1873 fun bin_expr2
: AExpr is abstract
1876 fun bin_op
: String is abstract
1878 redef fun accept_pretty_printer
(v
) do
1879 var can_inline
= v
.can_inline
(self)
1881 if not can_inline
then
1882 if (self isa ABinopExpr and bin_expr1
isa ABinopExpr) or
1883 (self isa AAndExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr)) or
1884 (self isa AOrExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr))
1886 bin_expr1
.force_block
= true
1906 redef class AAndExpr
1909 redef fun bin_expr1
do return n_expr
1910 redef fun bin_expr2
do return n_expr2
1911 redef fun bin_op
do return "and"
1917 redef fun bin_expr1
do return n_expr
1918 redef fun bin_expr2
do return n_expr2
1919 redef fun bin_op
do return "or"
1922 redef class AImpliesExpr
1925 redef fun bin_expr1
do return n_expr
1926 redef fun bin_expr2
do return n_expr2
1927 redef fun bin_op
do return "implies"
1930 redef class ABinopExpr
1933 redef fun bin_expr1
do return n_expr
1934 redef fun bin_expr2
do return n_expr2
1938 redef fun bin_op
do return "=="
1942 redef fun bin_op
do return ">="
1946 redef fun bin_op
do return ">>"
1950 redef fun bin_op
do return ">"
1954 redef fun bin_op
do return "<="
1958 redef fun bin_op
do return "<<"
1962 redef fun bin_op
do return "<"
1965 redef class AMinusExpr
1966 redef fun bin_op
do return "-"
1970 redef fun bin_op
do return "!="
1973 redef class APercentExpr
1974 redef fun bin_op
do return "%"
1977 redef class APlusExpr
1978 redef fun bin_op
do return "+"
1981 redef class ASlashExpr
1982 redef fun bin_op
do return "/"
1985 redef class AStarExpr
1986 redef fun bin_op
do return "*"
1989 redef class AStarstarExpr
1990 redef fun bin_op
do return "**"
1993 redef class AStarshipExpr
1994 redef fun bin_op
do return "<=>"
1997 redef class AIsaExpr
1998 redef fun accept_pretty_printer
(v
) do
2007 redef class AOrElseExpr
2008 redef fun accept_pretty_printer
(v
) do
2018 redef fun is_inlinable
do return true
2023 redef class AUminusExpr
2024 redef fun accept_pretty_printer
(v
) do
2030 redef class ANullExpr
2031 redef fun accept_pretty_printer
(v
) do v
.visit n_kwnull
2032 redef fun is_inlinable
do return true
2035 redef class AParExpr
2036 redef fun accept_pretty_printer
(v
) do
2043 redef class AArrayExpr
2044 redef fun accept_pretty_printer
(v
) do
2046 v
.visit_list n_exprs
2051 redef class ACrangeExpr
2052 redef fun accept_pretty_printer
(v
) do
2061 redef class AOrangeExpr
2062 redef fun accept_pretty_printer
(v
) do
2073 redef class AStringFormExpr
2074 redef fun accept_pretty_printer
(v
) do
2075 var can_inline
= v
.can_inline
(self)
2080 var text
= n_string
.text
2083 while i
< text
.length
do
2086 if v
.current_length
>= v
.max_size
and i
<= text
.length
- 3 then
2098 v
.current_token
= n_string
.next_token
2103 redef class ASuperstringExpr
2104 redef fun accept_pretty_printer
(v
) do
2105 for n_expr
in n_exprs
do v
.visit n_expr
2108 redef fun must_be_inline
do
2109 if super then return true
2111 if not n_exprs
.is_empty
then
2112 var first
= n_exprs
.first
2113 return first
isa AStringFormExpr and first
.n_string
.text
.has_prefix
("\"\
"\"")