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.
22 # The `PrettyPrinterVisitor` is used to visit a node and pretty print it.
24 # The main method here is `visit` that performs the pretty printing of a `ANode`.
26 # Because some tokens like `TComment` are not stored in the AST,
27 # we visit the AST like traditionnal visitor and also maintain a
28 # pointer to the `current_token` (actually the next one to be printed).
30 # Visited productions are in charges to move the token pointer using methods such as:
32 # * `consume`: print `current_token` and move to the next one
33 # * `skip`: move to the next token without printing the current one
34 # * `skip_to`: move to a specified token skipping all the tokens before
35 # * `catch_up`: consume all the tokens between `current_token` and a specified token
36 # * `finish_line`: consume all the tokens between `current_token` and the end of line
37 class PrettyPrinterVisitor
39 fun pretty
(n
: ANode): Template do
44 current_token
= n
.first_token
46 else if n
isa Token then
49 while p
!= null and not p
isa Prod do
53 current_token
= p
.first_token
57 return tpl
.as(not null)
60 # Pretty print the whole `nmodule` with comments before and after.
61 fun pretty_nmodule
(nmodule
: AModule): Template do
63 nmodule
.parentize_tokens
64 current_token
= nmodule
.location
.file
.first_token
66 catch_up nmodule
.location
.file
.last_token
68 return tpl
.as(not null)
71 # Prepare `self` for a new visit.
81 # Visit `n` if not null.
82 fun visit
(n
: nullable ANode) do
83 if n
== null then return
84 n
.accept_pretty_printer
self
87 # Visit a list of `Anode`.
88 fun visit_list
(n
: nullable ANodes[ANode]) do
89 if n
== null then return
90 n
.accept_pretty_printer
self
93 # Is the node inlinable and can fit on the line.
94 fun can_inline
(n
: nullable ANode): Bool do
95 if n
== null then return true
96 if n
.must_be_inline
then return true
97 if n
.must_be_block
then return false
99 if n
.collect_length
+ current_length
> max_size
then return false
100 # check block is inlinable
101 return n
.is_inlinable
104 # Collect all `TComment` between `from` and `to`.
105 fun collect_comments
(from
: nullable ANode, to
: nullable ANode): Array[TComment] do
106 var res
= new Array[TComment]
107 if from
isa Prod then from
= from
.first_token
108 if to
isa Prod then to
= to
.first_token
109 if from
== null or to
== null then return res
112 if from
isa TComment then res
.add from
113 from
= from
.as(Token).next_token
119 # Token under cursor.
121 # This is the next token to visit.
122 var current_token
: nullable Token = null
124 # Skip the `current_token`.
125 fun skip
do current_token
= current_token
.next_token
127 # Skip `current_token` until the end of line.
128 fun skip_line
do current_token
= current_token
.last_real_token_in_line
130 # Skip `current_token` until `target` is reached.
131 fun skip_to
(target
: nullable Token) do
132 if target
== null then return
133 while current_token
!= target
do skip
136 # Visit `current_token`.
137 fun consume
(token
: String) do
138 assert current_token
.text
== token
142 # Is there token to visit between `current_token` and `target`?
143 fun need_catch_up
(target
: nullable Token): Bool do
144 if target
== null then return false
145 return current_token
!= target
148 # Visit all tokens between `current_token` and `target`.
149 fun catch_up
(target
: nullable ANode) do
150 if target
== null then return
151 if current_token
== null then return
153 if target
isa Token then
155 else if target
isa Prod then
156 token
= target
.first_token
.as(not null)
160 assert current_token
.location
<= token
.location
161 while current_token
!= token
do visit current_token
164 # Visit all tokens between `current_token` and the end of line.
166 if current_token
isa TComment then
171 while current_token
isa TEol do skip
174 # The template under construction.
175 private var tpl
: nullable Template = null
177 # Current indent level.
180 # Size of a tabulation in spaces.
186 # Length of the current line.
187 var current_length
= 0
189 # Length of the previous line.
190 var previous_length
= 0
192 # Is the last line a blank line?
193 fun last_line_is_blank
: Bool do return previous_length
== 0
195 # Add `t` to current template.
196 fun add
(t
: String) do
197 if t
.is_empty
then return
198 while wait_addn
> 0 do
203 current_length
+= t
.length
208 if current_length
== 0 and last_line_is_blank
then return
209 previous_length
= current_length
214 # End of line chars are stored until another char is added.
215 # This avoid empty files with only a '`\n`'.
216 private var wait_addn
= 0
218 # Add `'\t' * indent`.
219 fun addt
do add
"\t" * indent
224 fun visit_recv
(n_expr
: AExpr) do
225 if not n_expr
isa AImplicitSelfExpr then
232 # Base framework redefs
234 redef class ANodes[E
]
235 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) do
237 var e_can_inline
= v
.can_inline
(e
)
240 if not e_can_inline
then
256 # Start visit of `self` using a `PrettyPrinterVisitor`
257 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) is abstract
259 # Collect the length (in `Char`) of the node.
260 private fun collect_length
: Int is abstract
262 # Is `self` printable in one line?
263 private fun is_inlinable
: Bool do return true
265 # Force `self` to be rendered as a block.
266 private var force_block
= false
268 # Does `self` have to be rendered as a block?
269 private fun must_be_block
: Bool do return force_block
271 # Force `self` to be rendered as a line.
272 private var force_inline
= false
274 # Does `self` have be rendered as a line?
275 private fun must_be_inline
: Bool do
276 if parent
!= null and parent
.must_be_inline
then return true
280 # Does `self` was written in one line before transformation?
281 private fun was_inline
: Bool is abstract
285 redef fun accept_pretty_printer
(v
) do
287 v
.current_token
= next_token
290 redef fun collect_length
do return text
.length
291 redef fun is_inlinable
do return true
292 redef fun was_inline
do return true
296 redef fun accept_pretty_printer
(v
) do v
.visit first_token
298 # The token where the production really start (skipping ADoc).
299 private fun start_token
: nullable Token do return first_token
301 # Collect all `TComment` contained in the production
302 # (between `start_token` and `end_token`).
303 private fun collect_comments
: Array[TComment] do
304 var res
= new Array[TComment]
305 if start_token
== null or last_token
== null then return res
306 var token
= start_token
308 while token
!= last_token
do
309 if token
isa TComment then res
.add token
310 token
= token
.next_token
316 redef fun collect_length
do
318 if start_token
== null or last_token
== null then return res
319 var token
= start_token
321 while token
!= last_token
do
322 res
+= token
.text
.length
323 token
= token
.next_token
326 res
+= token
.text
.length
330 redef fun was_inline
do
331 return first_token
.location
.line_start
== last_token
.location
.line_end
338 redef fun accept_pretty_printer
(v
) do
349 if is_last_in_group
then v
.addn
363 if next_token
isa TComment and is_first_in_group
then v
.addn
367 var prev_token
= self.prev_token
368 if prev_token
isa TComment and prev_token
.is_inline
and is_last_in_group
then v
.addn
375 # Is `self` part of an `ADoc`?
376 private fun is_adoc
: Bool do return parent
isa ADoc and parent
.parent
!= null
378 # Is `self` part of a licence?
379 private fun is_licence
: Bool do
380 var prev_token
= self.prev_token
382 if prev_token
== null then
384 else if prev_token
isa TComment then
385 return prev_token
.is_licence
391 # Is `self` starts and ends its line?
392 private fun is_inline
: Bool do
393 return self == first_real_token_in_line
and self == last_real_token_in_line
396 # Is `self` an orphan line (blank before and after)?
397 private fun is_orphan
: Bool do
398 return prev_token
isa TEol and
399 (prev_token
.prev_token
isa TEol or prev_token
.prev_token
isa TComment) and
403 # Is `self` the first comment of a group of comment?
404 private fun is_first_in_group
: Bool do return not prev_token
isa TComment
406 # Is `self` the last comment of a group of comments?
407 private fun is_last_in_group
: Bool do return not next_token
isa TComment
411 redef fun accept_pretty_printer
(v
) do for comment
in n_comment
do v
.visit comment
412 redef fun is_inlinable
do return n_comment
.length
<= 1
417 redef class AAnnotations
418 redef fun accept_pretty_printer
(v
) do
422 if v
.can_inline
(self) then
424 for n_item
in n_items
do
426 if n_item
!= n_items
.last
then
431 else if n_items
.length
> 1 then
435 for n_item
in n_items
do
444 if not was_inline
and v
.current_token
isa TKwend then v
.skip
447 redef fun is_inlinable
do
448 if not super then return false
449 for annot
in n_items
do if not annot
.is_inlinable
then return false
454 redef class AAnnotation
455 redef fun accept_pretty_printer
(v
) do
457 if not n_args
.is_empty
then
458 if n_opar
== null then
469 redef class ATypeExpr
470 redef fun accept_pretty_printer
(v
) do v
.visit n_type
476 redef fun accept_pretty_printer
(v
) do
477 v
.catch_up start_token
480 if not n_imports
.is_empty
then
483 for n_import
in n_imports
do
489 if not n_extern_code_blocks
.is_empty
then
492 for n_extern_block
in n_extern_code_blocks
do
493 v
.catch_up n_extern_block
494 v
.visit n_extern_block
496 if n_extern_block
!= n_extern_code_blocks
.last
then v
.addn
499 if not n_classdefs
.is_empty
then v
.addn
502 if not n_classdefs
.is_empty
then
505 for n_classdef
in n_classdefs
do
506 v
.catch_up n_classdef
508 if n_classdef
!= n_classdefs
.last
then v
.addn
516 redef fun start_token
do
517 if n_moduledecl
!= null then return n_moduledecl
.first_token
518 if not n_imports
.is_empty
then return n_imports
.first
.first_token
519 if not n_classdefs
.is_empty
then return n_classdefs
.first
.first_token
523 redef fun is_inlinable
do return false
526 redef class AModuledecl
527 redef fun accept_pretty_printer
(v
) do
533 if n_annotations
!= null then
534 var annot_inline
= v
.can_inline
(n_annotations
)
535 v
.visit n_annotations
537 if not annot_inline
then
538 if v
.current_token
isa TKwend then
552 redef class AModuleName
553 redef fun accept_pretty_printer
(v
) do
554 for path
in n_path
do
563 redef class ANoImport
564 redef fun accept_pretty_printer
(v
) do
573 redef class AStdImport
574 redef fun accept_pretty_printer
(v
) do
575 if not n_visibility
isa APublicVisibility then
590 redef class AClassdef
591 redef fun accept_pretty_printer
(v
) do
592 for n_propdef
in n_propdefs
do
595 if n_propdef
.n_doc
!= null or not v
.can_inline
(n_propdef
) then
596 if n_propdef
!= n_propdefs
.first
then v
.addn
598 if n_propdef
!= n_propdefs
.last
then v
.addn
606 redef class AStdClassdef
607 redef fun accept_pretty_printer
(v
) do
609 var can_inline
= v
.can_inline
(self)
611 if not n_visibility
isa APublicVisibility then
616 if n_kwredef
!= null then
625 if not n_formaldefs
.is_empty
then
627 v
.visit_list n_formaldefs
631 if n_extern_code_block
!= null then
633 v
.visit n_extern_code_block
639 if not n_superclasses
.is_empty
then
640 for n_superclass
in n_superclasses
do
650 for n_superclass
in n_superclasses
do
651 v
.catch_up n_superclass
658 if not n_superclasses
.is_empty
and not n_propdefs
.is_empty
then
673 redef fun is_inlinable
do
674 if not super then return false
675 if not n_propdefs
.is_empty
then return false
676 if n_superclasses
.length
> 1 then return false
677 if not collect_comments
.is_empty
then return false
681 redef fun start_token
do
682 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
683 if n_kwredef
!= null then return n_kwredef
684 return n_classkind
.first_token
688 redef class AAbstractClasskind
689 redef fun accept_pretty_printer
(v
) do
696 redef class AExternClasskind
697 redef fun accept_pretty_printer
(v
) do
704 redef class AFormaldef
705 redef fun accept_pretty_printer
(v
) do
708 if n_type
!= null then
717 redef fun accept_pretty_printer
(v
) do
718 if n_kwnullable
!= null then
725 if not n_types
.is_empty
then
733 redef class ASuperclass
734 redef fun accept_pretty_printer
(v
) do
744 redef fun accept_pretty_printer
(v
) do
748 if not n_visibility
isa APublicVisibility then
753 if n_kwredef
!= null then
759 redef fun start_token
do
760 if n_doc
== null then return super
761 return n_doc
.last_token
.next_token
765 redef class AAttrPropdef
766 redef fun accept_pretty_printer
(v
) do
772 if n_type
!= null then
778 if n_expr
!= null then
785 if n_annotations
!= null then v
.visit n_annotations
790 redef fun first_token
do
791 if n_doc
!= null then return n_doc
.first_token
792 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
793 if n_kwredef
!= null then return n_kwredef
797 redef fun is_inlinable
do return true
800 redef class ATypePropdef
801 redef fun accept_pretty_printer
(v
) do
813 redef fun is_inlinable
do return true
816 redef class AMethPropdef
817 redef fun accept_pretty_printer
(v
) do
818 # TODO: Handle extern annotations
820 var before
= v
.indent
821 var can_inline
= v
.can_inline
(self)
823 if n_kwinit
!= null then v
.visit n_kwinit
824 if n_kwmeth
!= null then v
.visit n_kwmeth
825 if n_kwnew
!= null then v
.visit n_kwnew
827 if not n_methid
== null then
834 if n_annotations
!= null then
835 v
.visit n_annotations
840 if n_extern_calls
!= null or n_extern_code_block
!= null then
841 if n_annotations
!= null then v
.adds
842 if n_extern_calls
!= null then v
.visit n_extern_calls
843 if n_extern_code_block
!= null then v
.visit n_extern_code_block
846 var n_block
= self.n_block
848 if n_block
!= null then
849 while not v
.current_token
isa TKwdo do v
.skip
850 if n_annotations
!= null then
851 if v
.can_inline
(n_annotations
) then
862 if n_block
isa ABlockExpr then
863 if n_block
.n_expr
.is_empty
then
864 v
.visit n_block
.n_kwend
866 v
.visit n_block
.n_expr
.first
867 v
.current_token
= n_block
.n_kwend
872 if v
.current_token
isa TKwend then v
.skip
879 if n_block
isa ABlockExpr then
880 n_block
.force_block
= true
882 v
.catch_up n_block
.n_kwend
891 if n_block
isa ABlockExpr then
892 v
.visit n_block
.n_kwend
901 assert v
.indent
== before
905 # * block is empty or can be inlined
906 # * contains no comments
907 redef fun is_inlinable
do
908 if not super then return false
909 if n_annotations
!= null and not n_annotations
.is_inlinable
then return false
910 if n_block
!= null and not n_block
.is_inlinable
then return false
911 if n_extern_calls
!= null and not n_extern_calls
.is_inlinable
then return false
912 if n_extern_code_block
!= null and not n_extern_code_block
.is_inlinable
then return false
913 if not collect_comments
.is_empty
then return false
918 redef class AMainMethPropdef
919 redef fun accept_pretty_printer
(v
) do
925 redef class ASignature
926 redef fun accept_pretty_printer
(v
) do
927 if not n_params
.is_empty
then
929 v
.visit_list n_params
933 if n_type
!= null then
942 redef fun accept_pretty_printer
(v
) do
945 if n_type
!= null then
951 if n_dotdotdot
!= null then v
.visit n_dotdotdot
957 redef class AExternCalls
958 redef fun accept_pretty_printer
(v
) do
959 var can_inline
= v
.can_inline
(self)
964 v
.visit_list n_extern_calls
969 v
.visit_list n_extern_calls
976 redef class AFullPropExternCall
977 redef fun accept_pretty_printer
(v
) do
984 redef class ALocalPropExternCall
985 redef fun accept_pretty_printer
(v
) do v
.visit n_methid
988 redef class AInitPropExternCall
989 redef fun accept_pretty_printer
(v
) do v
.visit n_type
992 redef class ACastAsExternCall
993 redef fun accept_pretty_printer
(v
) do
1003 redef class AAsNullableExternCall
1004 redef fun accept_pretty_printer
(v
) do
1009 v
.visit n_kwnullable
1013 redef class AAsNotNullableExternCall
1014 redef fun accept_pretty_printer
(v
) do
1021 v
.visit n_kwnullable
1025 redef class AExternCodeBlock
1026 redef fun accept_pretty_printer
(v
) do
1027 if n_in_language
!= null then
1028 v
.visit n_in_language
1032 v
.visit n_extern_code_segment
1035 redef fun is_inlinable
do
1036 if not super then return false
1037 return n_extern_code_segment
.is_inlinable
1041 redef class AInLanguage
1042 redef fun accept_pretty_printer
(v
) do
1049 redef class TExternCodeSegment
1050 redef fun accept_pretty_printer
(v
) do
1051 var can_inline
= v
.can_inline
(self)
1056 var text
= text
.substring
(2, text
.length
- 4)
1057 var lines
= text
.r_trim
.split
("\n")
1059 if text
.is_empty
then
1064 if not lines
.first
.trim
.is_empty
then
1072 for line
in lines
do
1081 v
.current_token
= next_token
1085 redef fun is_inlinable
do
1086 if not super then return false
1087 return location
.line_start
== location
.line_end
1093 redef class ABlockExpr
1094 redef fun accept_pretty_printer
(v
) do
1095 var before
= v
.indent
1096 var can_inline
= v
.can_inline
(self)
1098 if can_inline
and not n_expr
.is_empty
then
1099 v
.visit n_expr
.first
1102 for nexpr
in n_expr
do
1103 var expr_inline
= v
.can_inline
(nexpr
)
1104 if not expr_inline
and nexpr
!= n_expr
.first
then v
.addn
1110 if not expr_inline
and nexpr
!= n_expr
.last
then v
.addn
1114 assert v
.indent
== before
1117 redef fun is_inlinable
do
1118 if not super then return false
1119 if not collect_comments
.is_empty
then return false
1121 if not n_expr
.is_empty
then
1122 if n_expr
.length
> 1 then return false
1123 if not n_expr
.first
.is_inlinable
then return false
1131 redef fun accept_pretty_printer
(v
) do
1132 var before
= v
.indent
1133 var can_inline
= v
.can_inline
(self)
1137 if v
.can_inline
(n_expr
) then
1146 # skip comments before `then` token
1147 while not v
.current_token
isa TKwthen do v
.skip
1149 var n_else
= self.n_else
1153 if n_then
!= null then v
.visit n_then
1156 n_else
.force_inline
= true
1161 else if n_then
== null then
1165 v
.skip_to last_token
.last_real_token_in_line
1171 if n_then
!= null then
1172 if n_then
isa ABlockExpr then
1173 n_then
.force_block
= true
1183 while not v
.current_token
isa TKwelse do
1184 v
.consume v
.current_token
.text
1191 if n_else
isa AIfExpr then
1192 n_else
.force_block
= true
1200 if n_else
isa ABlockExpr then
1201 n_else
.force_block
= true
1209 if last_token
isa TKwend then
1210 v
.catch_up last_token
1221 if last_token
.location
>= v
.current_token
.location
then v
.catch_up last_token
1225 if v
.current_token
isa TKwend then v
.skip
1229 assert v
.indent
== before
1232 redef fun is_inlinable
do
1233 if not super then return false
1234 if n_then
!= null and not n_then
.is_inlinable
then return false
1235 var n_else
= self.n_else
1236 if (n_else
isa ABlockExpr and not n_else
.n_expr
.is_empty
) or
1237 (not n_else
isa ABlockExpr and n_else
!= null) then
1240 if not collect_comments
.is_empty
then return false
1244 # Does this `if` statement contains a `else` part?
1245 private fun has_else
(v
: PrettyPrinterVisitor): Bool do
1247 if n_else
== null then return false
1248 var n_kwelse
= collect_kwelse
1249 if n_kwelse
== null then return false
1251 if n_else
isa ABlockExpr then
1252 var comments
: Array[TComment]
1254 if n_then
== null then
1255 comments
= v
.collect_comments
(n_expr
.last_token
, n_else
.last_token
)
1257 comments
= v
.collect_comments
(n_then
.last_token
, n_else
.last_token
)
1260 if not comments
.is_empty
then return true
1261 return not n_else
.n_expr
.is_empty
1267 # Lookup for `else` token in `self`.
1268 private fun collect_kwelse
: nullable TKwelse do
1269 var token
= first_token
1271 while token
!= last_token
do
1272 if token
isa TKwelse then return token
1273 token
= token
.next_token
1280 # Used to factorize work on loops.
1281 private class ALoopHelper
1284 fun loop_block
: nullable ANode is abstract
1285 fun loop_label
: nullable ANode is abstract
1287 fun visit_loop_block
(v
: PrettyPrinterVisitor) do
1288 var n_block
= loop_block
1293 if n_block
isa ABlockExpr then
1294 n_block
.force_block
= true
1296 v
.catch_up n_block
.n_kwend
1299 v
.visit n_block
.n_kwend
1309 if loop_label
!= null then
1315 fun visit_loop_inline
(v
: PrettyPrinterVisitor) do
1316 var n_block
= loop_block
1319 if n_block
isa ABlockExpr then
1320 if n_block
.n_expr
.is_empty
then
1321 v
.visit n_block
.n_kwend
1323 v
.visit n_block
.n_expr
.first
1324 v
.current_token
= n_block
.n_kwend
1329 if v
.current_token
isa TKwend then v
.skip
1332 if loop_label
!= null then
1338 redef fun is_inlinable
do
1339 var n_block
= loop_block
1340 if not super then return false
1341 if n_block
isa ABlockExpr and not n_block
.is_inlinable
then return false
1342 if not collect_comments
.is_empty
then return false
1347 redef class ALoopExpr
1350 redef fun loop_block
do return n_block
1351 redef fun loop_label
do return n_label
1353 redef fun accept_pretty_printer
(v
) do
1354 var can_inline
= v
.can_inline
(self)
1356 if can_inline
then visit_loop_inline v
else visit_loop_block v
1360 redef class AWhileExpr
1363 redef fun loop_block
do return n_block
1364 redef fun loop_label
do return n_label
1366 redef fun accept_pretty_printer
(v
) do
1367 var can_inline
= v
.can_inline
(self)
1373 if can_inline
then visit_loop_inline v
else visit_loop_block v
1380 redef fun loop_block
do return n_block
1381 redef fun loop_label
do return n_label
1383 redef fun accept_pretty_printer
(v
) do
1384 var can_inline
= v
.can_inline
(self)
1386 if can_inline
then visit_loop_inline v
else visit_loop_block v
1390 redef class AForExpr
1393 redef fun loop_block
do return n_block
1394 redef fun loop_label
do return n_label
1396 redef fun accept_pretty_printer
(v
) do
1397 var can_inline
= v
.can_inline
(self)
1401 for n_id
in n_ids
do
1403 if n_id
!= n_ids
.last
then v
.add
", "
1412 if can_inline
then visit_loop_inline v
else visit_loop_block v
1416 redef class ABreakExpr
1417 redef fun accept_pretty_printer
(v
) do
1420 if n_expr
!= null then
1425 if n_label
!= null then
1431 redef fun is_inlinable
do return true
1434 redef class AContinueExpr
1435 redef fun accept_pretty_printer
(v
) do
1436 v
.visit n_kwcontinue
1438 if n_expr
!= null then
1443 if n_label
!= null then
1449 redef fun is_inlinable
do return true
1454 redef class ASendExpr
1455 redef fun is_inlinable
do return true
1458 redef class ACallExpr
1459 redef fun accept_pretty_printer
(v
) do
1460 var can_inline
= v
.can_inline
(self)
1463 if not n_expr
isa AImplicitSelfExpr and not can_inline
then
1471 if not n_args
.n_exprs
.is_empty
then
1472 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1474 if v
.current_token
isa TOpar then v
.skip
1475 v
.visit n_args
.n_exprs
.first
1476 if v
.current_token
isa TCpar then v
.skip
1478 if v
.current_token
isa TOpar then
1484 v
.visit_list n_args
.n_exprs
1485 if v
.current_token
isa TCpar then v
.consume
")"
1490 # Is the call alone on its line?
1491 fun is_stmt
: Bool do return parent
isa ABlockExpr
1494 redef class ACallAssignExpr
1495 redef fun accept_pretty_printer
(v
) do
1499 if not n_args
.n_exprs
.is_empty
then
1501 v
.visit_list n_args
.n_exprs
1512 redef class ACallReassignExpr
1513 redef fun accept_pretty_printer
(v
) do
1517 if not n_args
.n_exprs
.is_empty
then
1519 v
.visit_list n_args
.n_exprs
1530 redef class ABraExpr
1531 redef fun accept_pretty_printer
(v
) do
1534 if not n_args
.n_exprs
.is_empty
then
1536 v
.visit_list n_args
.n_exprs
1542 redef class ABraAssignExpr
1543 redef fun accept_pretty_printer
(v
) do
1546 if not n_args
.n_exprs
.is_empty
then
1548 v
.visit_list n_args
.n_exprs
1559 redef class ABraReassignExpr
1560 redef fun accept_pretty_printer
(v
) do
1563 if not n_args
.n_exprs
.is_empty
then
1565 v
.visit_list n_args
.n_exprs
1576 redef class AAssignMethid
1577 redef fun accept_pretty_printer
(v
) do
1583 redef class ABraMethid
1584 redef fun accept_pretty_printer
(v
) do
1590 redef class ABraassignMethid
1591 redef fun accept_pretty_printer
(v
) do
1598 redef class AInitExpr
1599 redef fun accept_pretty_printer
(v
) do
1600 if not n_expr
isa AImplicitSelfExpr then
1607 if not n_args
.n_exprs
.is_empty
then
1609 v
.visit_list n_args
.n_exprs
1615 redef class ANewExpr
1616 redef fun accept_pretty_printer
(v
) do
1617 var can_inline
= v
.can_inline
(self)
1622 if n_id
!= null then
1625 if not can_inline
then
1634 if not n_args
.n_exprs
.is_empty
then
1636 v
.visit_list n_args
.n_exprs
1641 redef fun is_inlinable
do return true
1646 redef class AAttrExpr
1647 redef fun accept_pretty_printer
(v
) do
1652 redef fun is_inlinable
do return true
1655 redef class AAttrAssignExpr
1656 redef fun accept_pretty_printer
(v
) do
1666 redef class AAttrReassignExpr
1667 redef fun accept_pretty_printer
(v
) do
1679 redef class AVardeclExpr
1680 redef fun accept_pretty_printer
(v
) do
1685 if n_type
!= null then
1691 if n_expr
!= null then
1699 redef fun is_inlinable
do return true
1702 redef class AVarAssignExpr
1703 redef fun accept_pretty_printer
(v
) do
1712 redef class AAssertExpr
1713 redef fun accept_pretty_printer
(v
) do
1714 var can_inline
= v
.can_inline
(self)
1717 if n_id
!= null then
1725 var n_else
= self.n_else
1727 if n_else
!= null then
1737 if n_else
isa ABlockExpr then
1739 n_else
.force_block
= true
1743 v
.visit n_else
.n_kwend
1757 redef fun is_inlinable
do
1758 if not super then return false
1759 if n_else
!= null and not n_else
.is_inlinable
then return false
1764 redef class AReturnExpr
1765 redef fun accept_pretty_printer
(v
) do
1768 if n_expr
!= null then
1775 redef class ASuperExpr
1776 redef fun accept_pretty_printer
(v
) do
1779 if not n_args
.n_exprs
.is_empty
then
1780 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1782 if v
.current_token
isa TOpar then v
.skip
1783 v
.visit n_args
.n_exprs
.first
1784 if v
.current_token
isa TCpar then v
.skip
1786 if v
.current_token
isa TOpar then
1792 v
.visit_list n_args
.n_exprs
1793 if v
.current_token
isa TCpar then v
.consume
")"
1798 # Is the call alone on its line?
1799 fun is_stmt
: Bool do return self.first_token
.is_starting_line
1801 redef fun is_inlinable
do return true
1804 redef class AOnceExpr
1805 redef fun accept_pretty_printer
(v
) do
1811 redef fun is_inlinable
do return true
1814 redef class AAbortExpr
1815 redef fun accept_pretty_printer
(v
) do v
.visit n_kwabort
1816 redef fun is_inlinable
do return true
1819 redef class ANotExpr
1820 redef fun accept_pretty_printer
(v
) do
1827 redef class AAsCastExpr
1828 redef fun accept_pretty_printer
(v
) do
1838 redef class AAsNotnullExpr
1839 redef fun accept_pretty_printer
(v
) do
1853 # Used to factorize work on Or, And, Implies and Binop expressions.
1854 private class ABinOpHelper
1857 fun bin_expr1
: AExpr is abstract
1858 fun bin_expr2
: AExpr is abstract
1861 fun bin_op
: String is abstract
1863 redef fun accept_pretty_printer
(v
) do
1864 var can_inline
= v
.can_inline
(self)
1866 if not can_inline
then
1867 if (self isa ABinopExpr and bin_expr1
isa ABinopExpr) or
1868 (self isa AAndExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr)) or
1869 (self isa AOrExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr))
1871 bin_expr1
.force_block
= true
1891 redef class AAndExpr
1894 redef fun bin_expr1
do return n_expr
1895 redef fun bin_expr2
do return n_expr2
1896 redef fun bin_op
do return "and"
1902 redef fun bin_expr1
do return n_expr
1903 redef fun bin_expr2
do return n_expr2
1904 redef fun bin_op
do return "or"
1907 redef class AImpliesExpr
1910 redef fun bin_expr1
do return n_expr
1911 redef fun bin_expr2
do return n_expr2
1912 redef fun bin_op
do return "implies"
1915 redef class ABinopExpr
1918 redef fun bin_expr1
do return n_expr
1919 redef fun bin_expr2
do return n_expr2
1923 redef fun bin_op
do return "=="
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 "<"
1950 redef class AMinusExpr
1951 redef fun bin_op
do return "-"
1955 redef fun bin_op
do return "!="
1958 redef class APercentExpr
1959 redef fun bin_op
do return "%"
1962 redef class APlusExpr
1963 redef fun bin_op
do return "+"
1966 redef class ASlashExpr
1967 redef fun bin_op
do return "/"
1970 redef class AStarExpr
1971 redef fun bin_op
do return "*"
1974 redef class AStarstarExpr
1975 redef fun bin_op
do return "**"
1978 redef class AStarshipExpr
1979 redef fun bin_op
do return "<=>"
1982 redef class AIsaExpr
1983 redef fun accept_pretty_printer
(v
) do
1992 redef class AOrElseExpr
1993 redef fun accept_pretty_printer
(v
) do
2003 redef fun is_inlinable
do return true
2008 redef class AUminusExpr
2009 redef fun accept_pretty_printer
(v
) do
2015 redef class ANullExpr
2016 redef fun accept_pretty_printer
(v
) do v
.visit n_kwnull
2017 redef fun is_inlinable
do return true
2020 redef class AParExpr
2021 redef fun accept_pretty_printer
(v
) do
2028 redef class AArrayExpr
2029 redef fun accept_pretty_printer
(v
) do
2031 v
.visit_list n_exprs
.n_exprs
2036 redef class ACrangeExpr
2037 redef fun accept_pretty_printer
(v
) do
2046 redef class AOrangeExpr
2047 redef fun accept_pretty_printer
(v
) do
2058 redef class AStringFormExpr
2059 redef fun accept_pretty_printer
(v
) do
2060 var can_inline
= v
.can_inline
(self)
2065 var text
= n_string
.text
2068 while i
< text
.length
do
2071 if v
.current_length
>= v
.max_size
and i
<= text
.length
- 3 then
2083 v
.current_token
= n_string
.next_token
2088 redef class ASuperstringExpr
2089 redef fun accept_pretty_printer
(v
) do
2090 for n_expr
in n_exprs
do v
.visit n_expr
2093 redef fun must_be_inline
do
2094 if super then return true
2096 if not n_exprs
.is_empty
then
2097 var first
= n_exprs
.first
2098 return first
isa AStringFormExpr and first
.n_string
.text
.has_prefix
("\"\
"\"")