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
82 if skip_empty
then tpl
.add
"\n"
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 visit
(current_token
)
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
226 if skip_empty
then wait_addn
+= 1
229 # Perform `addn` even if not `skip_empty`.
231 if current_length
== 0 and last_line_is_blank
then return
232 previous_length
= current_length
237 # End of line chars are stored until another char is added.
238 # This avoid empty files with only a '`\n`'.
239 private var wait_addn
= 0
241 # Add `'\t' * indent`.
242 fun addt
do add
"\t" * indent
247 # Visit explicit receiver, implicit self will be ignored.
248 fun visit_recv
(n_expr
: AExpr) do
249 if not n_expr
isa AImplicitSelfExpr then
255 # Do we break string literals that are too long?
256 var break_strings
= false is public
writable
258 # Do we force `do` to be on the same line as the method signature?
259 var inline_do
= false is public
writable
261 # Do we force the deletion of empty lines?
262 var skip_empty
= false is public
writable
265 # Base framework redefs
267 redef class ANodes[E
]
268 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) do
270 var e_can_inline
= v
.can_inline
(e
)
273 if not e_can_inline
then
290 # Start visit of `self` using a `PrettyPrinterVisitor`
291 private fun accept_pretty_printer
(v
: PrettyPrinterVisitor) is abstract
293 # Collect the length (in `Char`) of the node.
294 private fun collect_length
: Int is abstract
296 # Is `self` printable in one line?
297 private fun is_inlinable
: Bool do return true
299 # Force `self` to be rendered as a block.
300 private var force_block
= false
302 # Does `self` have to be rendered as a block?
303 private fun must_be_block
: Bool do return force_block
305 # Force `self` to be rendered as a line.
306 private var force_inline
= false
308 # Does `self` have be rendered as a line?
309 private fun must_be_inline
: Bool do
310 if parent
!= null and parent
.must_be_inline
then return true
314 # Does `self` was written in one line before transformation?
315 private fun was_inline
: Bool is abstract
319 redef fun accept_pretty_printer
(v
) do
321 v
.current_token
= next_token
324 redef fun collect_length
do return text
.length
325 redef fun is_inlinable
do return true
326 redef fun was_inline
do return true
330 redef fun accept_pretty_printer
(v
) do
335 v
.current_token
= next_token
341 redef fun accept_pretty_printer
(v
) do v
.visit first_token
343 # The token where the production really start (skipping ADoc).
344 private fun start_token
: nullable Token do return first_token
346 # Collect all `TComment` contained in the production
347 # (between `start_token` and `end_token`).
348 private fun collect_comments
: Array[TComment] do
349 var res
= new Array[TComment]
350 if start_token
== null or last_token
== null then return res
351 var token
= start_token
353 while token
!= last_token
do
354 if token
isa TComment then res
.add token
355 token
= token
.next_token
361 redef fun collect_length
do
363 if start_token
== null or last_token
== null then return res
364 var token
= start_token
366 while token
!= last_token
do
367 res
+= token
.text
.length
368 token
= token
.next_token
371 res
+= token
.text
.length
375 redef fun was_inline
do
376 return start_token
.location
.line_start
== last_token
.location
.line_end
383 redef fun accept_pretty_printer
(v
) do
394 if is_last_in_group
then v
.addn
408 if next_token
isa TComment and is_first_in_group
then v
.addn
412 var prev_token
= self.prev_token
413 if prev_token
isa TComment and prev_token
.is_inline
and is_last_in_group
then v
.addn
418 if not v
.skip_empty
then v
.forcen
421 # Is `self` part of an `ADoc`?
422 private fun is_adoc
: Bool do return parent
isa ADoc and parent
.parent
!= null
424 # Is `self` part of a licence?
425 private fun is_licence
: Bool do
426 var prev_token
= self.prev_token
428 if prev_token
== null then
430 else if prev_token
isa TComment then
431 return prev_token
.is_licence
437 # Is `self` starts and ends its line?
438 private fun is_inline
: Bool do
439 return self == first_real_token_in_line
and self == last_real_token_in_line
442 # Is `self` an orphan line (blank before and after)?
443 private fun is_orphan
: Bool do
444 return prev_token
isa TEol and
445 (prev_token
.prev_token
isa TEol or prev_token
.prev_token
isa TComment) and
449 # Is `self` the first comment of a group of comment?
450 private fun is_first_in_group
: Bool do return not prev_token
isa TComment
452 # Is `self` the last comment of a group of comments?
453 private fun is_last_in_group
: Bool do return not next_token
isa TComment
457 redef fun accept_pretty_printer
(v
) do for comment
in n_comment
do v
.visit comment
458 redef fun is_inlinable
do return n_comment
.length
<= 1
463 redef class AAnnotations
464 redef fun accept_pretty_printer
(v
) do
467 if v
.can_inline
(self) then
469 for n_item
in n_items
do
471 if n_item
!= n_items
.last
then
475 if not was_inline
then
477 if v
.current_token
isa TKwend then v
.skip
482 for n_item
in n_items
do
486 if n_item
!= n_items
.last
then
498 redef fun is_inlinable
do
499 if not super then return false
500 for annot
in n_items
do if not annot
.is_inlinable
then return false
505 redef class AAnnotation
506 redef fun accept_pretty_printer
(v
) do
507 if n_visibility
!= null and not n_visibility
isa APublicVisibility then
512 if not n_args
.is_empty
then
513 if n_opar
== null then
524 redef class ATypeExpr
525 redef fun accept_pretty_printer
(v
) do v
.visit n_type
531 redef fun accept_pretty_printer
(v
) do
532 v
.catch_up start_token
535 if not n_imports
.is_empty
then
536 if v
.skip_empty
then v
.addn
538 for n_import
in n_imports
do
544 if not n_extern_code_blocks
.is_empty
then
547 for n_extern_block
in n_extern_code_blocks
do
548 v
.catch_up n_extern_block
549 v
.visit n_extern_block
551 if n_extern_block
!= n_extern_code_blocks
.last
then v
.addn
554 if not n_classdefs
.is_empty
then v
.addn
557 if not n_classdefs
.is_empty
then
558 if v
.skip_empty
then v
.addn
560 for n_classdef
in n_classdefs
do
561 v
.catch_up n_classdef
563 if n_classdef
!= n_classdefs
.last
then v
.addn
571 redef fun start_token
do
572 if n_moduledecl
!= null then return n_moduledecl
.first_token
573 if not n_imports
.is_empty
then return n_imports
.first
.first_token
574 if not n_classdefs
.is_empty
then return n_classdefs
.first
.first_token
578 redef fun is_inlinable
do return false
581 redef class AModuledecl
582 redef fun accept_pretty_printer
(v
) do
588 if n_annotations
!= null then
589 var annot_inline
= v
.can_inline
(n_annotations
)
590 v
.visit n_annotations
592 if not annot_inline
then
593 if v
.current_token
isa TKwend then
603 if v
.skip_empty
then v
.addn
607 redef class AModuleName
608 redef fun accept_pretty_printer
(v
) do
609 for path
in n_path
do
618 redef class ANoImport
619 redef fun accept_pretty_printer
(v
) do
624 if v
.skip_empty
then v
.addn
628 redef class AStdImport
629 redef fun accept_pretty_printer
(v
) do
630 if not n_visibility
isa APublicVisibility then
639 if v
.skip_empty
then v
.addn
645 redef class AClassdef
646 redef fun accept_pretty_printer
(v
) do
647 for n_propdef
in n_propdefs
do
650 if n_propdef
.n_doc
!= null or not v
.can_inline
(n_propdef
) then
651 if v
.skip_empty
and n_propdef
!= n_propdefs
.first
then v
.addn
653 if v
.skip_empty
and n_propdef
!= n_propdefs
.last
then v
.addn
661 redef class AStdClassdef
662 redef fun accept_pretty_printer
(v
) do
664 var can_inline
= v
.can_inline
(self)
666 if not n_visibility
isa APublicVisibility then
671 if n_kwredef
!= null then
680 if not n_formaldefs
.is_empty
then
682 v
.visit_list n_formaldefs
686 if n_extern_code_block
!= null then
688 v
.visit n_extern_code_block
694 if not n_propdefs
.is_empty
then
695 for n_superclass
in n_propdefs
do
702 if v
.skip_empty
then v
.addn
712 if v
.skip_empty
then v
.addn
716 redef fun is_inlinable
do
717 if not super then return false
718 # FIXME: repair pretty-printing one-liner classes
719 if n_propdefs
.length
> 0 then return false
720 #if n_propdefs.length == 1 and not n_propdefs.first isa ASuperPropdef then return false
721 if not collect_comments
.is_empty
then return false
725 redef fun start_token
do
726 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
727 if n_kwredef
!= null then return n_kwredef
728 return n_classkind
.first_token
732 redef class AAbstractClasskind
733 redef fun accept_pretty_printer
(v
) do
740 redef class AExternClasskind
741 redef fun accept_pretty_printer
(v
) do
748 redef class AFormaldef
749 redef fun accept_pretty_printer
(v
) do
752 if n_type
!= null then
761 redef fun accept_pretty_printer
(v
) do
762 if n_kwnullable
!= null then
769 if not n_types
.is_empty
then
780 redef fun accept_pretty_printer
(v
) do
784 if not n_visibility
isa nullable APublicVisibility then
789 if n_kwredef
!= null then
795 # Factorize annotations visit for all APropdef.
797 # Return true if annotations were inlined.
798 fun visit_annotations
(v
: PrettyPrinterVisitor, n_annotations
: nullable AAnnotations): Bool do
799 var res
= v
.can_inline
(n_annotations
)
800 if n_annotations
!= null then v
.visit n_annotations
804 # Factorize block visit for APropdefs.
806 # Were annotations printed inline? If so, we need to print the block differently.
807 fun visit_block
(v
: PrettyPrinterVisitor, n_block
: nullable AExpr, annot_inline
: Bool) do
808 # var can_inline = v.can_inline(n_block)
809 if n_block
== null then return
810 if n_annotations
!= null and not annot_inline
then
815 while not v
.current_token
isa TKwdo do v
.skip
817 var token
= v
.current_token
820 if token
isa TEol then
822 if not v
.can_inline
(n_block
) then
828 token
= v
.current_token
829 if token
isa TKwdo then break
831 if annot_inline
and do_inline
then v
.adds
834 if v
.can_inline
(n_block
) and do_inline
then
837 if n_block
isa ABlockExpr then
838 if n_block
.n_expr
.is_empty
then
839 v
.visit n_block
.n_kwend
841 v
.visit n_block
.n_expr
.first
842 v
.current_token
= n_block
.n_kwend
847 if v
.current_token
isa TKwend then v
.skip
858 if n_block
isa ABlockExpr then
859 n_block
.force_block
= true
861 v
.catch_up n_block
.n_kwend
870 if n_block
isa ABlockExpr then
871 v
.visit n_block
.n_kwend
879 redef fun start_token
do
880 if n_doc
== null then return super
881 return n_doc
.last_token
.next_token
885 redef class AAttrPropdef
886 redef fun accept_pretty_printer
(v
) do
892 if n_type
!= null then
898 if n_expr
!= null then
905 var annot_inline
= visit_annotations
(v
, n_annotations
)
906 visit_block
(v
, n_block
, annot_inline
)
911 redef fun first_token
do
912 if n_doc
!= null then return n_doc
.first_token
913 if not n_visibility
isa APublicVisibility then return n_visibility
.first_token
914 if n_kwredef
!= null then return n_kwredef
918 redef fun is_inlinable
do return true
921 redef class ATypePropdef
922 redef fun accept_pretty_printer
(v
) do
930 visit_annotations
(v
, n_annotations
)
935 redef fun is_inlinable
do return true
938 redef class AMethPropdef
939 redef fun accept_pretty_printer
(v
) do
940 # TODO: Handle extern annotations
942 var before
= v
.indent
944 if n_kwinit
!= null then v
.visit n_kwinit
945 if n_kwmeth
!= null then v
.visit n_kwmeth
946 if n_kwnew
!= null then v
.visit n_kwnew
948 if not n_methid
== null then
955 var annot_inline
= visit_annotations
(v
, n_annotations
)
957 if n_extern_calls
!= null or n_extern_code_block
!= null then
959 if n_extern_calls
!= null then v
.visit n_extern_calls
960 if n_extern_code_block
!= null then v
.visit n_extern_code_block
963 visit_block
(v
, n_block
, annot_inline
)
965 assert v
.indent
== before
969 # * block is empty or can be inlined
970 # * contains no comments
971 redef fun is_inlinable
do
972 if not super then return false
973 if n_annotations
!= null and not n_annotations
.is_inlinable
then return false
974 if n_block
!= null and not n_block
.is_inlinable
then return false
975 if n_extern_calls
!= null and not n_extern_calls
.is_inlinable
then return false
976 if n_extern_code_block
!= null and not n_extern_code_block
.is_inlinable
then return false
977 if not collect_comments
.is_empty
then return false
982 redef class AMainMethPropdef
983 redef fun accept_pretty_printer
(v
) do
985 if v
.skip_empty
then v
.addn
989 redef class ASuperPropdef
990 redef fun accept_pretty_printer
(v
) do
995 visit_annotations
(v
, n_annotations
)
1000 redef fun is_inlinable
do return true
1003 redef class ASignature
1004 redef fun accept_pretty_printer
(v
) do
1005 if not n_params
.is_empty
then
1007 v
.visit_list n_params
1011 if n_type
!= null then
1020 redef fun accept_pretty_printer
(v
) do
1023 if n_type
!= null then
1029 if n_dotdotdot
!= null then v
.visit n_dotdotdot
1035 redef class AExternCalls
1036 redef fun accept_pretty_printer
(v
) do
1037 var can_inline
= v
.can_inline
(self)
1042 v
.visit_list n_extern_calls
1048 v
.visit_list n_extern_calls
1055 redef class AFullPropExternCall
1056 redef fun accept_pretty_printer
(v
) do
1063 redef class ALocalPropExternCall
1064 redef fun accept_pretty_printer
(v
) do v
.visit n_methid
1067 redef class AInitPropExternCall
1068 redef fun accept_pretty_printer
(v
) do v
.visit n_type
1071 redef class ACastAsExternCall
1072 redef fun accept_pretty_printer
(v
) do
1082 redef class AAsNullableExternCall
1083 redef fun accept_pretty_printer
(v
) do
1088 v
.visit n_kwnullable
1092 redef class AAsNotNullableExternCall
1093 redef fun accept_pretty_printer
(v
) do
1100 v
.visit n_kwnullable
1104 redef class AExternCodeBlock
1105 redef fun accept_pretty_printer
(v
) do
1106 if n_in_language
!= null then
1107 v
.visit n_in_language
1111 v
.visit n_extern_code_segment
1114 redef fun is_inlinable
do
1115 if not super then return false
1116 return n_extern_code_segment
.is_inlinable
1120 redef class AInLanguage
1121 redef fun accept_pretty_printer
(v
) do
1128 redef class TExternCodeSegment
1129 redef fun accept_pretty_printer
(v
) do
1130 var can_inline
= v
.can_inline
(self)
1135 var text
= text
.substring
(2, text
.length
- 4)
1136 var lines
= text
.r_trim
.split
("\n")
1138 if text
.is_empty
then
1143 if not lines
.first
.trim
.is_empty
then
1151 for line
in lines
do
1160 v
.current_token
= next_token
1164 redef fun is_inlinable
do
1165 if not super then return false
1166 return location
.line_start
== location
.line_end
1172 redef class ABlockExpr
1173 redef fun accept_pretty_printer
(v
) do
1174 var before
= v
.indent
1175 var can_inline
= v
.can_inline
(self)
1177 if can_inline
and not n_expr
.is_empty
then
1178 v
.visit n_expr
.first
1181 for nexpr
in n_expr
do
1182 var expr_inline
= v
.can_inline
(nexpr
)
1183 if not expr_inline
and nexpr
!= n_expr
.first
then v
.addn
1189 if not expr_inline
and nexpr
!= n_expr
.last
then v
.addn
1193 assert v
.indent
== before
1196 redef fun is_inlinable
do
1197 if not super then return false
1198 if not collect_comments
.is_empty
then return false
1200 if not n_expr
.is_empty
then
1201 if n_expr
.length
> 1 then return false
1202 if not n_expr
.first
.is_inlinable
then return false
1210 redef fun accept_pretty_printer
(v
) do
1211 var before
= v
.indent
1212 var can_inline
= v
.can_inline
(self)
1216 if v
.can_inline
(n_expr
) then
1225 # skip comments before `then` token
1226 while not v
.current_token
isa TKwthen do v
.skip
1228 var n_else
= self.n_else
1232 if n_then
!= null then v
.visit n_then
1235 n_else
.force_inline
= true
1240 else if n_then
== null then
1243 v
.skip_to last_token
.last_real_token_in_line
1248 else if not v
.skip_empty
and n_then
!= null and
1249 n_then
.was_inline
and
1250 n_then
.location
.line_end
== location
.line_start
then
1251 v
.forcen
# Xymus fucking syntax
1257 if n_then
!= null then
1258 if n_then
isa ABlockExpr then
1259 n_then
.force_block
= true
1264 if n_then
.was_inline
then
1273 while not v
.current_token
isa TKwelse do
1274 v
.consume v
.current_token
.text
1281 if n_else
isa AIfExpr then
1282 n_else
.force_block
= true
1294 if n_else
isa ABlockExpr then
1295 n_else
.force_block
= true
1300 if n_else
.was_inline
then
1307 if last_token
isa TKwend then
1308 v
.catch_up last_token
1319 if last_token
.location
>= v
.current_token
.location
then v
.catch_up last_token
1323 if v
.current_token
isa TKwend then v
.skip
1327 assert v
.indent
== before
1330 redef fun is_inlinable
do
1331 if not super then return false
1332 if n_then
!= null and not n_then
.is_inlinable
then return false
1333 var n_else
= self.n_else
1334 if (n_else
isa ABlockExpr and not n_else
.n_expr
.is_empty
) or
1335 (not n_else
isa ABlockExpr and n_else
!= null) then
1338 if not collect_comments
.is_empty
then return false
1342 # Does this `if` statement contains a `else` part?
1343 private fun has_else
(v
: PrettyPrinterVisitor): Bool do
1345 if n_else
== null then return false
1346 var n_kwelse
= collect_kwelse
1347 if n_kwelse
== null then return false
1349 if n_else
isa ABlockExpr then
1350 var comments
: Array[TComment]
1352 if n_then
== null then
1353 comments
= v
.collect_comments
(n_expr
.last_token
, n_else
.last_token
)
1355 comments
= v
.collect_comments
(n_then
.last_token
, n_else
.last_token
)
1358 if not comments
.is_empty
then return true
1359 return not n_else
.n_expr
.is_empty
1365 # Lookup for `else` token in `self`.
1366 private fun collect_kwelse
: nullable TKwelse do
1367 var token
= first_token
1369 while token
!= last_token
do
1370 if token
isa TKwelse then return token
1371 token
= token
.next_token
1378 # Used to factorize work on loops.
1379 private class ALoopHelper
1382 fun loop_block
: nullable ANode is abstract
1383 fun loop_label
: nullable ANode is abstract
1385 fun visit_loop_block
(v
: PrettyPrinterVisitor) do
1386 var n_block
= loop_block
1391 if n_block
isa ABlockExpr then
1392 n_block
.force_block
= true
1394 v
.catch_up n_block
.n_kwend
1397 v
.visit n_block
.n_kwend
1407 if loop_label
!= null then
1413 fun visit_loop_inline
(v
: PrettyPrinterVisitor) do
1414 var n_block
= loop_block
1417 if n_block
isa ABlockExpr then
1418 if n_block
.n_expr
.is_empty
then
1419 v
.visit n_block
.n_kwend
1421 v
.visit n_block
.n_expr
.first
1422 v
.current_token
= n_block
.n_kwend
1427 if v
.current_token
isa TKwend then v
.skip
1430 if loop_label
!= null then
1436 redef fun is_inlinable
do
1437 var n_block
= loop_block
1438 if not super then return false
1439 if n_block
isa ABlockExpr and not n_block
.is_inlinable
then return false
1440 if not collect_comments
.is_empty
then return false
1445 redef class ALoopExpr
1448 redef fun loop_block
do return n_block
1449 redef fun loop_label
do return n_label
1451 redef fun accept_pretty_printer
(v
) do
1452 var can_inline
= v
.can_inline
(self)
1454 if can_inline
then visit_loop_inline v
else visit_loop_block v
1458 redef class AWhileExpr
1461 redef fun loop_block
do return n_block
1462 redef fun loop_label
do return n_label
1464 redef fun accept_pretty_printer
(v
) do
1465 var can_inline
= v
.can_inline
(self)
1471 if can_inline
then visit_loop_inline v
else visit_loop_block v
1478 redef fun loop_block
do return n_block
1479 redef fun loop_label
do return n_label
1481 redef fun accept_pretty_printer
(v
) do
1482 var can_inline
= v
.can_inline
(self)
1484 if can_inline
then visit_loop_inline v
else visit_loop_block v
1488 redef class AForExpr
1491 redef fun loop_block
do return n_block
1492 redef fun loop_label
do return n_label
1494 redef fun accept_pretty_printer
(v
) do
1495 var can_inline
= v
.can_inline
(self)
1499 for n_id
in n_ids
do
1501 if n_id
!= n_ids
.last
then v
.add
", "
1510 if can_inline
then visit_loop_inline v
else visit_loop_block v
1514 redef class ABreakExpr
1515 redef fun accept_pretty_printer
(v
) do
1518 if n_expr
!= null then
1523 if n_label
!= null then
1529 redef fun is_inlinable
do return true
1532 redef class AContinueExpr
1533 redef fun accept_pretty_printer
(v
) do
1534 v
.visit n_kwcontinue
1536 if n_expr
!= null then
1541 if n_label
!= null then
1547 redef fun is_inlinable
do return true
1552 redef class ASendExpr
1553 redef fun is_inlinable
do return true
1556 redef class ACallExpr
1557 redef fun accept_pretty_printer
(v
) do
1558 var can_inline
= v
.can_inline
(self)
1561 if not n_expr
isa AImplicitSelfExpr and not can_inline
then
1568 if not n_args
.n_exprs
.is_empty
then
1569 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1571 if v
.current_token
isa TOpar then v
.skip
1572 v
.visit n_args
.n_exprs
.first
1573 if v
.current_token
isa TCpar then v
.skip
1575 if v
.current_token
isa TOpar then
1581 v
.visit_list n_args
.n_exprs
1582 if v
.current_token
isa TCpar then v
.consume
")"
1587 # Is the call alone on its line?
1588 fun is_stmt
: Bool do return parent
isa ABlockExpr
1591 redef class ACallAssignExpr
1592 redef fun accept_pretty_printer
(v
) do
1596 if not n_args
.n_exprs
.is_empty
then
1598 v
.visit_list n_args
.n_exprs
1609 redef class ACallReassignExpr
1610 redef fun accept_pretty_printer
(v
) do
1614 if not n_args
.n_exprs
.is_empty
then
1616 v
.visit_list n_args
.n_exprs
1627 redef class ABraExpr
1628 redef fun accept_pretty_printer
(v
) do
1631 if not n_args
.n_exprs
.is_empty
then
1633 v
.visit_list n_args
.n_exprs
1639 redef class ABraAssignExpr
1640 redef fun accept_pretty_printer
(v
) do
1643 if not n_args
.n_exprs
.is_empty
then
1645 v
.visit_list n_args
.n_exprs
1656 redef class ABraReassignExpr
1657 redef fun accept_pretty_printer
(v
) do
1660 if not n_args
.n_exprs
.is_empty
then
1662 v
.visit_list n_args
.n_exprs
1673 redef class AAssignMethid
1674 redef fun accept_pretty_printer
(v
) do
1680 redef class ABraMethid
1681 redef fun accept_pretty_printer
(v
) do
1687 redef class ABraassignMethid
1688 redef fun accept_pretty_printer
(v
) do
1695 redef class AInitExpr
1696 redef fun accept_pretty_printer
(v
) do
1697 if not n_expr
isa AImplicitSelfExpr then
1704 if not n_args
.n_exprs
.is_empty
then
1706 v
.visit_list n_args
.n_exprs
1712 redef class ANewExpr
1713 redef fun accept_pretty_printer
(v
) do
1714 var can_inline
= v
.can_inline
(self)
1719 if n_id
!= null then
1722 if not can_inline
then
1732 if not n_args
.n_exprs
.is_empty
then
1734 v
.visit_list n_args
.n_exprs
1739 redef fun is_inlinable
do return true
1744 redef class AAttrExpr
1745 redef fun accept_pretty_printer
(v
) do
1750 redef fun is_inlinable
do return true
1753 redef class AAttrAssignExpr
1754 redef fun accept_pretty_printer
(v
) do
1764 redef class AAttrReassignExpr
1765 redef fun accept_pretty_printer
(v
) do
1777 redef class AVardeclExpr
1778 redef fun accept_pretty_printer
(v
) do
1783 if n_type
!= null then
1789 if n_expr
!= null then
1797 redef fun is_inlinable
do return true
1800 redef class AVarAssignExpr
1801 redef fun accept_pretty_printer
(v
) do
1810 redef class AAssertExpr
1811 redef fun accept_pretty_printer
(v
) do
1812 var can_inline
= v
.can_inline
(self)
1815 if n_id
!= null then
1823 var n_else
= self.n_else
1825 if n_else
!= null then
1836 if n_else
isa ABlockExpr then
1837 n_else
.force_block
= true
1841 v
.visit n_else
.n_kwend
1854 redef fun is_inlinable
do
1855 if not super then return false
1856 if n_else
!= null and not n_else
.is_inlinable
then return false
1861 redef class AReturnExpr
1862 redef fun accept_pretty_printer
(v
) do
1865 if n_expr
!= null then
1872 redef class ASuperExpr
1873 redef fun accept_pretty_printer
(v
) do
1876 if not n_args
.n_exprs
.is_empty
then
1877 if is_stmt
and n_args
.n_exprs
.length
== 1 then
1879 if v
.current_token
isa TOpar then v
.skip
1880 v
.visit n_args
.n_exprs
.first
1881 if v
.current_token
isa TCpar then v
.skip
1883 if v
.current_token
isa TOpar then
1889 v
.visit_list n_args
.n_exprs
1890 if v
.current_token
isa TCpar then v
.consume
")"
1895 # Is the call alone on its line?
1896 fun is_stmt
: Bool do return self.first_token
.is_starting_line
1898 redef fun is_inlinable
do return true
1901 redef class AOnceExpr
1902 redef fun accept_pretty_printer
(v
) do
1908 redef fun is_inlinable
do return true
1911 redef class AAbortExpr
1912 redef fun accept_pretty_printer
(v
) do v
.visit n_kwabort
1913 redef fun is_inlinable
do return true
1916 redef class ANotExpr
1917 redef fun accept_pretty_printer
(v
) do
1924 redef class AAsCastExpr
1925 redef fun accept_pretty_printer
(v
) do
1935 redef class AAsNotnullExpr
1936 redef fun accept_pretty_printer
(v
) do
1950 # Used to factorize work on Or, And, Implies and Binop expressions.
1951 private class ABinOpHelper
1954 fun bin_expr1
: AExpr is abstract
1955 fun bin_expr2
: AExpr is abstract
1958 fun bin_op
: String is abstract
1960 redef fun accept_pretty_printer
(v
) do
1961 var can_inline
= v
.can_inline
(self)
1963 if not can_inline
then
1964 if (self isa ABinopExpr and bin_expr1
isa ABinopExpr) or
1965 (self isa AAndExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr)) or
1966 (self isa AOrExpr and (bin_expr1
isa AAndExpr or bin_expr1
isa AOrExpr))
1968 bin_expr1
.force_block
= true
1989 redef class AAndExpr
1992 redef fun bin_expr1
do return n_expr
1993 redef fun bin_expr2
do return n_expr2
1994 redef fun bin_op
do return "and"
2000 redef fun bin_expr1
do return n_expr
2001 redef fun bin_expr2
do return n_expr2
2002 redef fun bin_op
do return "or"
2005 redef class AImpliesExpr
2008 redef fun bin_expr1
do return n_expr
2009 redef fun bin_expr2
do return n_expr2
2010 redef fun bin_op
do return "implies"
2013 redef class ABinopExpr
2016 redef fun bin_expr1
do return n_expr
2017 redef fun bin_expr2
do return n_expr2
2021 redef fun bin_op
do return "=="
2025 redef fun bin_op
do return ">="
2029 redef fun bin_op
do return ">>"
2033 redef fun bin_op
do return ">"
2037 redef fun bin_op
do return "<="
2041 redef fun bin_op
do return "<<"
2045 redef fun bin_op
do return "<"
2048 redef class AMinusExpr
2049 redef fun bin_op
do return "-"
2053 redef fun bin_op
do return "!="
2056 redef class APercentExpr
2057 redef fun bin_op
do return "%"
2060 redef class APlusExpr
2061 redef fun bin_op
do return "+"
2064 redef class ASlashExpr
2065 redef fun bin_op
do return "/"
2068 redef class AStarExpr
2069 redef fun bin_op
do return "*"
2072 redef class AStarstarExpr
2073 redef fun bin_op
do return "**"
2076 redef class AStarshipExpr
2077 redef fun bin_op
do return "<=>"
2080 redef class AIsaExpr
2081 redef fun accept_pretty_printer
(v
) do
2090 redef class AOrElseExpr
2091 redef fun accept_pretty_printer
(v
) do
2101 redef fun is_inlinable
do return true
2106 redef class AUminusExpr
2107 redef fun accept_pretty_printer
(v
) do
2113 redef class ANullExpr
2114 redef fun accept_pretty_printer
(v
) do v
.visit n_kwnull
2115 redef fun is_inlinable
do return true
2118 redef class AParExpr
2119 redef fun accept_pretty_printer
(v
) do
2126 redef class AArrayExpr
2127 redef fun accept_pretty_printer
(v
) do
2129 v
.visit_list n_exprs
2134 redef class ACrangeExpr
2135 redef fun accept_pretty_printer
(v
) do
2144 redef class AOrangeExpr
2145 redef fun accept_pretty_printer
(v
) do
2156 redef class AStringFormExpr
2157 redef fun accept_pretty_printer
(v
) do
2158 if not v
.break_strings
then
2159 # n_string.force_inline = true
2163 if v
.can_inline
(self) then
2164 n_string
.force_inline
= true
2167 var text
= n_string
.text
2170 while i
< text
.length
do
2173 if v
.current_length
>= v
.max_size
and i
<= text
.length
- 3 then
2189 v
.current_token
= n_string
.next_token
2194 redef class ASuperstringExpr
2195 redef fun accept_pretty_printer
(v
) do
2196 for n_expr
in n_exprs
do
2197 if not v
.break_strings
then
2198 n_expr
.force_inline
= true
2204 redef fun must_be_inline
do
2205 if super then return true
2207 if not n_exprs
.is_empty
then
2208 var first
= n_exprs
.first
2209 return first
isa AStringFormExpr and first
.n_string
.text
.has_prefix
("\"\
"\"")