nitpretty: splits nitpretty into two modules
[nit.git] / src / pretty.nit
1 # This file is part of NIT ( http://www.nitlanguage.org ).
2 #
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
6 #
7 # http://www.apache.org/licenses/LICENSE-2.0
8 #
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.
14
15 module pretty
16
17 import template
18 import toolcontext
19 import modelbuilder
20 import astutil
21
22 # The `PrettyPrinterVisitor` is used to visit a node and pretty print it.
23 #
24 # The main method here is `visit` that performs the pretty printing of a `ANode`.
25 #
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).
29 #
30 # Visited productions are in charges to move the token pointer using methods such as:
31 #
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
38 # Pretty print `n`.
39 fun pretty(n: ANode): Template do
40 clear
41 n.parentize_tokens
42
43 if n isa Prod then
44 current_token = n.first_token
45 visit n
46 else if n isa Token then
47 var p = n.parent
48
49 while p != null and not p isa Prod do
50 p = p.parent
51 end
52
53 current_token = p.first_token
54 visit p
55 end
56
57 return tpl.as(not null)
58 end
59
60 # Pretty print the whole `nmodule` with comments before and after.
61 fun pretty_nmodule(nmodule: AModule): Template do
62 clear
63 nmodule.parentize_tokens
64 current_token = nmodule.location.file.first_token
65 visit nmodule
66 catch_up nmodule.location.file.last_token
67 tpl.add "\n"
68 return tpl.as(not null)
69 end
70
71 # Prepare `self` for a new visit.
72 private fun clear do
73 tpl = new Template
74 current_token = null
75 indent = 0
76 current_length = 0
77 previous_length = 0
78 wait_addn = 0
79 end
80
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
85 end
86
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
91 end
92
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
98 # check length
99 if n.collect_length + current_length > max_size then return false
100 # check block is inlinable
101 return n.is_inlinable
102 end
103
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
110
111 while from != to do
112 if from isa TComment then res.add from
113 from = from.as(Token).next_token
114 end
115
116 return res
117 end
118
119 # Token under cursor.
120 #
121 # This is the next token to visit.
122 var current_token: nullable Token = null
123
124 # Skip the `current_token`.
125 fun skip do current_token = current_token.next_token
126
127 # Skip `current_token` until the end of line.
128 fun skip_line do current_token = current_token.last_real_token_in_line
129
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
134 end
135
136 # Visit `current_token`.
137 fun consume(token: String) do
138 assert current_token.text == token
139 visit current_token
140 end
141
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
146 end
147
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
152 var token: Token
153 if target isa Token then
154 token = target
155 else if target isa Prod then
156 token = target.first_token.as(not null)
157 else
158 abort
159 end
160 assert current_token.location <= token.location
161 while current_token != token do visit current_token
162 end
163
164 # Visit all tokens between `current_token` and the end of line.
165 fun finish_line do
166 if current_token isa TComment then
167 adds
168 visit current_token
169 end
170
171 while current_token isa TEol do skip
172 end
173
174 # The template under construction.
175 private var tpl: nullable Template = null
176
177 # Current indent level.
178 var indent = 0
179
180 # Size of a tabulation in spaces.
181 var tab_size = 8
182
183 # Max line size.
184 var max_size = 80
185
186 # Length of the current line.
187 var current_length = 0
188
189 # Length of the previous line.
190 var previous_length = 0
191
192 # Is the last line a blank line?
193 fun last_line_is_blank: Bool do return previous_length == 0
194
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
199 tpl.add "\n"
200 wait_addn -= 1
201 end
202 tpl.add t
203 current_length += t.length
204 end
205
206 # Add a `'\n'`.
207 fun addn do
208 if current_length == 0 and last_line_is_blank then return
209 previous_length = current_length
210 current_length = 0
211 wait_addn += 1
212 end
213
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
217
218 # Add `'\t' * indent`.
219 fun addt do add "\t" * indent
220
221 # Add a space.
222 fun adds do add " "
223
224 fun visit_recv(n_expr: AExpr) do
225 if not n_expr isa AImplicitSelfExpr then
226 visit n_expr
227 consume "."
228 end
229 end
230 end
231
232 # Base framework redefs
233
234 redef class ANodes[E]
235 private fun accept_pretty_printer(v: PrettyPrinterVisitor) do
236 for e in self do
237 var e_can_inline = v.can_inline(e)
238
239 if e != first then
240 if not e_can_inline then
241 v.add ","
242 v.addn
243 v.addt
244 v.addt
245 else
246 v.add ", "
247 end
248 end
249
250 v.visit e
251 end
252 end
253 end
254
255 redef class ANode
256 # Start visit of `self` using a `PrettyPrinterVisitor`
257 private fun accept_pretty_printer(v: PrettyPrinterVisitor) is abstract
258
259 # Collect the length (in `Char`) of the node.
260 private fun collect_length: Int is abstract
261
262 # Is `self` printable in one line?
263 private fun is_inlinable: Bool do return true
264
265 # Force `self` to be rendered as a block.
266 private var force_block = false
267
268 # Does `self` have to be rendered as a block?
269 private fun must_be_block: Bool do return force_block
270
271 # Force `self` to be rendered as a line.
272 private var force_inline = false
273
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
277 return force_inline
278 end
279
280 # Does `self` was written in one line before transformation?
281 private fun was_inline: Bool is abstract
282 end
283
284 redef class Token
285 redef fun accept_pretty_printer(v) do
286 v.add text.trim
287 v.current_token = next_token
288 end
289
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
293 end
294
295 redef class Prod
296 redef fun accept_pretty_printer(v) do v.visit first_token
297
298 # The token where the production really start (skipping ADoc).
299 private fun start_token: nullable Token do return first_token
300
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
307
308 while token != last_token do
309 if token isa TComment then res.add token
310 token = token.next_token
311 end
312
313 return res
314 end
315
316 redef fun collect_length do
317 var res = 0
318 if start_token == null or last_token == null then return res
319 var token = start_token
320
321 while token != last_token do
322 res += token.text.length
323 token = token.next_token
324 end
325
326 res += token.text.length
327 return res
328 end
329
330 redef fun was_inline do
331 return first_token.location.line_start == last_token.location.line_end
332 end
333 end
334
335 # Comments
336
337 redef class TComment
338 redef fun accept_pretty_printer(v) do
339 if is_adoc then
340 v.addt
341 super
342 v.addn
343 return
344 end
345
346 if is_licence then
347 super
348 v.addn
349 if is_last_in_group then v.addn
350 return
351 end
352
353 if is_orphan then
354 v.addn
355 v.addt
356 super
357 v.addn
358 v.addn
359 return
360 end
361
362 if is_inline then
363 if next_token isa TComment and is_first_in_group then v.addn
364 v.addt
365 super
366 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
369 return
370 end
371
372 super
373 end
374
375 # Is `self` part of an `ADoc`?
376 private fun is_adoc: Bool do return parent isa ADoc and parent.parent != null
377
378 # Is `self` part of a licence?
379 private fun is_licence: Bool do
380 var prev_token = self.prev_token
381
382 if prev_token == null then
383 return true
384 else if prev_token isa TComment then
385 return prev_token.is_licence
386 else
387 return false
388 end
389 end
390
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
394 end
395
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
400 next_token isa TEol
401 end
402
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
405
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
408 end
409
410 redef class ADoc
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
413 end
414
415 # Annotations
416
417 redef class AAnnotations
418 redef fun accept_pretty_printer(v) do
419 v.adds
420 v.consume "is"
421
422 if v.can_inline(self) then
423 v.adds
424 for n_item in n_items do
425 v.visit n_item
426 if n_item != n_items.last then
427 v.add ", "
428 end
429 end
430 v.finish_line
431 else if n_items.length > 1 then
432 v.addn
433 v.indent += 1
434
435 for n_item in n_items do
436 v.addt
437 v.visit n_item
438 v.finish_line
439 v.addn
440 end
441
442 v.indent -= 1
443 end
444 if not was_inline and v.current_token isa TKwend then v.skip
445 end
446
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
450 return true
451 end
452 end
453
454 redef class AAnnotation
455 redef fun accept_pretty_printer(v) do
456 v.visit n_atid
457 if not n_args.is_empty then
458 if n_opar == null then
459 v.adds
460 else
461 v.visit n_opar
462 end
463 v.visit_list n_args
464 v.visit n_cpar
465 end
466 end
467 end
468
469 redef class ATypeExpr
470 redef fun accept_pretty_printer(v) do v.visit n_type
471 end
472
473 # Modules
474
475 redef class AModule
476 redef fun accept_pretty_printer(v) do
477 v.catch_up start_token
478 v.visit n_moduledecl
479
480 if not n_imports.is_empty then
481 v.addn
482
483 for n_import in n_imports do
484 v.catch_up n_import
485 v.visit n_import
486 end
487 end
488
489 if not n_extern_code_blocks.is_empty then
490 v.addn
491
492 for n_extern_block in n_extern_code_blocks do
493 v.catch_up n_extern_block
494 v.visit n_extern_block
495 v.addn
496 if n_extern_block != n_extern_code_blocks.last then v.addn
497 end
498
499 if not n_classdefs.is_empty then v.addn
500 end
501
502 if not n_classdefs.is_empty then
503 v.addn
504
505 for n_classdef in n_classdefs do
506 v.catch_up n_classdef
507 v.visit n_classdef
508 if n_classdef != n_classdefs.last then v.addn
509 end
510 end
511
512 assert v.indent == 0
513 end
514
515 # Skip doc if any.
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
520 return first_token
521 end
522
523 redef fun is_inlinable do return false
524 end
525
526 redef class AModuledecl
527 redef fun accept_pretty_printer(v) do
528 v.visit n_doc
529 v.visit n_kwmodule
530 v.adds
531 v.visit n_name
532
533 if n_annotations != null then
534 var annot_inline = v.can_inline(n_annotations)
535 v.visit n_annotations
536
537 if not annot_inline then
538 if v.current_token isa TKwend then
539 v.consume "end"
540 v.finish_line
541 else
542 v.add "end"
543 end
544 end
545 end
546
547 v.finish_line
548 v.addn
549 end
550 end
551
552 redef class AModuleName
553 redef fun accept_pretty_printer(v) do
554 for path in n_path do
555 v.visit path
556 v.add "::"
557 end
558
559 v.visit n_id
560 end
561 end
562
563 redef class ANoImport
564 redef fun accept_pretty_printer(v) do
565 v.visit n_kwimport
566 v.adds
567 v.visit n_kwend
568 v.finish_line
569 v.addn
570 end
571 end
572
573 redef class AStdImport
574 redef fun accept_pretty_printer(v) do
575 if not n_visibility isa APublicVisibility then
576 v.visit n_visibility
577 v.adds
578 end
579
580 v.visit n_kwimport
581 v.adds
582 v.visit n_name
583 v.finish_line
584 v.addn
585 end
586 end
587
588 # Classes
589
590 redef class AClassdef
591 redef fun accept_pretty_printer(v) do
592 for n_propdef in n_propdefs do
593 v.catch_up n_propdef
594
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
597 v.visit n_propdef
598 if n_propdef != n_propdefs.last then v.addn
599 else
600 v.visit n_propdef
601 end
602 end
603 end
604 end
605
606 redef class AStdClassdef
607 redef fun accept_pretty_printer(v) do
608 v.visit n_doc
609 var can_inline = v.can_inline(self)
610
611 if not n_visibility isa APublicVisibility then
612 v.visit n_visibility
613 v.adds
614 end
615
616 if n_kwredef != null then
617 v.visit n_kwredef
618 v.adds
619 end
620
621 v.visit n_classkind
622 v.adds
623 v.visit n_id
624
625 if not n_formaldefs.is_empty then
626 v.consume "["
627 v.visit_list n_formaldefs
628 v.consume "]"
629 end
630
631 if n_extern_code_block != null then
632 v.adds
633 v.visit n_extern_code_block
634 end
635
636 if can_inline then
637 v.adds
638
639 if not n_superclasses.is_empty then
640 for n_superclass in n_superclasses do
641 v.visit n_superclass
642 v.adds
643 end
644 end
645 else
646 v.finish_line
647 v.addn
648 v.indent += 1
649
650 for n_superclass in n_superclasses do
651 v.catch_up n_superclass
652 v.addt
653 v.visit n_superclass
654 v.finish_line
655 v.addn
656 end
657
658 if not n_superclasses.is_empty and not n_propdefs.is_empty then
659 v.addn
660 end
661
662 super
663 v.catch_up n_kwend
664 v.indent -= 1
665 end
666
667 v.visit n_kwend
668 v.finish_line
669 v.addn
670 assert v.indent == 0
671 end
672
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
678 return true
679 end
680
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
685 end
686 end
687
688 redef class AAbstractClasskind
689 redef fun accept_pretty_printer(v) do
690 v.visit n_kwabstract
691 v.adds
692 v.visit n_kwclass
693 end
694 end
695
696 redef class AExternClasskind
697 redef fun accept_pretty_printer(v) do
698 v.visit n_kwextern
699 v.adds
700 v.visit n_kwclass
701 end
702 end
703
704 redef class AFormaldef
705 redef fun accept_pretty_printer(v) do
706 v.visit n_id
707
708 if n_type != null then
709 v.consume ":"
710 v.adds
711 v.visit n_type
712 end
713 end
714 end
715
716 redef class AType
717 redef fun accept_pretty_printer(v) do
718 if n_kwnullable != null then
719 v.visit n_kwnullable
720 v.adds
721 end
722
723 v.visit n_id
724
725 if not n_types.is_empty then
726 v.consume "["
727 v.visit_list n_types
728 v.consume "]"
729 end
730 end
731 end
732
733 redef class ASuperclass
734 redef fun accept_pretty_printer(v) do
735 v.visit n_kwsuper
736 v.adds
737 v.visit n_type
738 end
739 end
740
741 # Properties
742
743 redef class APropdef
744 redef fun accept_pretty_printer(v) do
745 v.visit n_doc
746 v.addt
747
748 if not n_visibility isa APublicVisibility then
749 v.visit n_visibility
750 v.adds
751 end
752
753 if n_kwredef != null then
754 v.visit n_kwredef
755 v.adds
756 end
757 end
758
759 redef fun start_token do
760 if n_doc == null then return super
761 return n_doc.last_token.next_token
762 end
763 end
764
765 redef class AAttrPropdef
766 redef fun accept_pretty_printer(v) do
767 super
768 v.visit n_kwvar
769 v.adds
770 v.visit n_id2
771
772 if n_type != null then
773 v.consume ":"
774 v.adds
775 v.visit n_type
776 end
777
778 if n_expr != null then
779 v.adds
780 v.consume "="
781 v.adds
782 v.visit n_expr
783 end
784
785 if n_annotations != null then v.visit n_annotations
786 v.finish_line
787 v.addn
788 end
789
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
794 return n_kwvar
795 end
796
797 redef fun is_inlinable do return true
798 end
799
800 redef class ATypePropdef
801 redef fun accept_pretty_printer(v) do
802 super
803 v.visit n_kwtype
804 v.adds
805 v.visit n_id
806 v.consume ":"
807 v.adds
808 v.visit n_type
809 v.finish_line
810 v.addn
811 end
812
813 redef fun is_inlinable do return true
814 end
815
816 redef class AMethPropdef
817 redef fun accept_pretty_printer(v) do
818 # TODO: Handle extern annotations
819
820 var before = v.indent
821 var can_inline = v.can_inline(self)
822 super
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
826
827 if not n_methid == null then
828 v.adds
829 v.visit n_methid
830 end
831
832 v.visit n_signature
833
834 if n_annotations != null then
835 v.visit n_annotations
836 else
837 v.adds
838 end
839
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
844 end
845
846 var n_block = self.n_block
847
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
852 v.adds
853 else
854 v.addt
855 end
856 end
857 v.consume "do"
858
859 if can_inline then
860 v.adds
861
862 if n_block isa ABlockExpr then
863 if n_block.n_expr.is_empty then
864 v.visit n_block.n_kwend
865 else
866 v.visit n_block.n_expr.first
867 v.current_token = n_block.n_kwend
868 v.skip
869 end
870 else
871 v.visit n_block
872 if v.current_token isa TKwend then v.skip
873 end
874 else
875 v.finish_line
876 v.addn
877 v.indent += 1
878
879 if n_block isa ABlockExpr then
880 n_block.force_block = true
881 v.visit n_block
882 v.catch_up n_block.n_kwend
883 else
884 v.addt
885 v.visit n_block
886 v.addn
887 end
888
889 v.indent -= 1
890 v.addt
891 if n_block isa ABlockExpr then
892 v.visit n_block.n_kwend
893 else
894 v.add "end"
895 end
896 end
897 end
898
899 v.finish_line
900 v.addn
901 assert v.indent == before
902 end
903
904 # Can be inlined if:
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
914 return true
915 end
916 end
917
918 redef class AMainMethPropdef
919 redef fun accept_pretty_printer(v) do
920 v.visit n_block
921 v.addn
922 end
923 end
924
925 redef class ASignature
926 redef fun accept_pretty_printer(v) do
927 if not n_params.is_empty then
928 v.consume "("
929 v.visit_list n_params
930 v.consume ")"
931 end
932
933 if n_type != null then
934 v.consume ":"
935 v.adds
936 v.visit n_type
937 end
938 end
939 end
940
941 redef class AParam
942 redef fun accept_pretty_printer(v) do
943 v.visit n_id
944
945 if n_type != null then
946 v.consume ":"
947 v.adds
948 v.visit n_type
949 end
950
951 if n_dotdotdot != null then v.visit n_dotdotdot
952 end
953 end
954
955 # Extern
956
957 redef class AExternCalls
958 redef fun accept_pretty_printer(v) do
959 var can_inline = v.can_inline(self)
960 v.visit n_kwimport
961
962 if can_inline then
963 v.adds
964 v.visit_list n_extern_calls
965 else
966 v.addn
967 v.addt
968 v.addt
969 v.visit_list n_extern_calls
970 end
971
972 v.adds
973 end
974 end
975
976 redef class AFullPropExternCall
977 redef fun accept_pretty_printer(v) do
978 v.visit n_type
979 v.visit n_dot
980 v.visit n_methid
981 end
982 end
983
984 redef class ALocalPropExternCall
985 redef fun accept_pretty_printer(v) do v.visit n_methid
986 end
987
988 redef class AInitPropExternCall
989 redef fun accept_pretty_printer(v) do v.visit n_type
990 end
991
992 redef class ACastAsExternCall
993 redef fun accept_pretty_printer(v) do
994 v.visit n_from_type
995 v.visit n_dot
996 v.visit n_kwas
997 v.consume "("
998 v.visit n_to_type
999 v.consume ")"
1000 end
1001 end
1002
1003 redef class AAsNullableExternCall
1004 redef fun accept_pretty_printer(v) do
1005 v.visit n_type
1006 v.consume "."
1007 v.visit n_kwas
1008 v.adds
1009 v.visit n_kwnullable
1010 end
1011 end
1012
1013 redef class AAsNotNullableExternCall
1014 redef fun accept_pretty_printer(v) do
1015 v.visit n_type
1016 v.consume "."
1017 v.visit n_kwas
1018 v.adds
1019 v.visit n_kwnot
1020 v.adds
1021 v.visit n_kwnullable
1022 end
1023 end
1024
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
1029 v.adds
1030 end
1031
1032 v.visit n_extern_code_segment
1033 end
1034
1035 redef fun is_inlinable do
1036 if not super then return false
1037 return n_extern_code_segment.is_inlinable
1038 end
1039 end
1040
1041 redef class AInLanguage
1042 redef fun accept_pretty_printer(v) do
1043 v.visit n_kwin
1044 v.adds
1045 v.visit n_string
1046 end
1047 end
1048
1049 redef class TExternCodeSegment
1050 redef fun accept_pretty_printer(v) do
1051 var can_inline = v.can_inline(self)
1052
1053 if can_inline then
1054 super
1055 else
1056 var text = text.substring(2, text.length - 4)
1057 var lines = text.r_trim.split("\n")
1058
1059 if text.is_empty then
1060 v.add "`\{`\}"
1061 else
1062 v.add "`\{"
1063
1064 if not lines.first.trim.is_empty then
1065 v.addn
1066 lines.first.l_trim
1067 v.indent += 1
1068 v.addt
1069 v.indent -= 1
1070 end
1071
1072 for line in lines do
1073 v.add line.r_trim
1074 v.addn
1075 end
1076
1077 v.addt
1078 v.add "`\}"
1079 end
1080
1081 v.current_token = next_token
1082 end
1083 end
1084
1085 redef fun is_inlinable do
1086 if not super then return false
1087 return location.line_start == location.line_end
1088 end
1089 end
1090
1091 # Blocks
1092
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)
1097
1098 if can_inline and not n_expr.is_empty then
1099 v.visit n_expr.first
1100 v.finish_line
1101 else
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
1105 v.catch_up nexpr
1106 v.addt
1107 v.visit nexpr
1108 v.finish_line
1109 v.addn
1110 if not expr_inline and nexpr != n_expr.last then v.addn
1111 end
1112 end
1113
1114 assert v.indent == before
1115 end
1116
1117 redef fun is_inlinable do
1118 if not super then return false
1119 if not collect_comments.is_empty then return false
1120
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
1124 end
1125
1126 return true
1127 end
1128 end
1129
1130 redef class AIfExpr
1131 redef fun accept_pretty_printer(v) do
1132 var before = v.indent
1133 var can_inline = v.can_inline(self)
1134 v.visit n_kwif
1135 v.adds
1136
1137 if v.can_inline(n_expr) then
1138 v.visit n_expr
1139 v.adds
1140 else
1141 v.visit n_expr
1142 v.addn
1143 v.addt
1144 end
1145
1146 # skip comments before `then` token
1147 while not v.current_token isa TKwthen do v.skip
1148 v.consume "then"
1149 var n_else = self.n_else
1150
1151 if can_inline then
1152 v.adds
1153 if n_then != null then v.visit n_then
1154
1155 if has_else(v) then
1156 n_else.force_inline = true
1157 v.adds
1158 v.consume "else"
1159 v.adds
1160 v.visit n_else
1161 else if n_then == null then
1162 v.add "end"
1163 end
1164
1165 v.skip_to last_token.last_real_token_in_line
1166 else
1167 v.finish_line
1168 v.addn
1169 v.indent += 1
1170
1171 if n_then != null then
1172 if n_then isa ABlockExpr then
1173 n_then.force_block = true
1174 v.visit n_then
1175 else
1176 v.addt
1177 v.visit n_then
1178 v.addn
1179 end
1180 end
1181
1182 if has_else(v) then
1183 while not v.current_token isa TKwelse do
1184 v.consume v.current_token.text
1185 end
1186
1187 v.indent -= 1
1188 v.addt
1189 v.consume "else"
1190
1191 if n_else isa AIfExpr then
1192 n_else.force_block = true
1193 v.adds
1194 v.visit n_else
1195 else
1196 v.finish_line
1197 v.addn
1198 v.indent += 1
1199
1200 if n_else isa ABlockExpr then
1201 n_else.force_block = true
1202 v.visit n_else
1203 else
1204 v.addt
1205 v.visit n_else
1206 v.addn
1207 end
1208
1209 if last_token isa TKwend then
1210 v.catch_up last_token
1211 v.indent -= 1
1212 v.addt
1213 v.consume "end"
1214 else
1215 v.indent -= 1
1216 v.addt
1217 v.add "end"
1218 end
1219 end
1220 else
1221 if last_token.location >= v.current_token.location then v.catch_up last_token
1222 v.indent -= 1
1223 v.addt
1224 v.add "end"
1225 if v.current_token isa TKwend then v.skip
1226 end
1227 end
1228
1229 assert v.indent == before
1230 end
1231
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
1238 return false
1239 end
1240 if not collect_comments.is_empty then return false
1241 return true
1242 end
1243
1244 # Does this `if` statement contains a `else` part?
1245 private fun has_else(v: PrettyPrinterVisitor): Bool do
1246 var n_else = n_else
1247 if n_else == null then return false
1248 var n_kwelse = collect_kwelse
1249 if n_kwelse == null then return false
1250
1251 if n_else isa ABlockExpr then
1252 var comments: Array[TComment]
1253
1254 if n_then == null then
1255 comments = v.collect_comments(n_expr.last_token, n_else.last_token)
1256 else
1257 comments = v.collect_comments(n_then.last_token, n_else.last_token)
1258 end
1259
1260 if not comments.is_empty then return true
1261 return not n_else.n_expr.is_empty
1262 end
1263
1264 return true
1265 end
1266
1267 # Lookup for `else` token in `self`.
1268 private fun collect_kwelse: nullable TKwelse do
1269 var token = first_token
1270
1271 while token != last_token do
1272 if token isa TKwelse then return token
1273 token = token.next_token
1274 end
1275
1276 return null
1277 end
1278 end
1279
1280 # Used to factorize work on loops.
1281 private class ALoopHelper
1282 super AExpr
1283
1284 fun loop_block: nullable ANode is abstract
1285 fun loop_label: nullable ANode is abstract
1286
1287 fun visit_loop_block(v: PrettyPrinterVisitor) do
1288 var n_block = loop_block
1289 v.finish_line
1290 v.addn
1291 v.indent += 1
1292
1293 if n_block isa ABlockExpr then
1294 n_block.force_block = true
1295 v.visit n_block
1296 v.catch_up n_block.n_kwend
1297 v.indent -= 1
1298 v.addt
1299 v.visit n_block.n_kwend
1300 else
1301 v.addt
1302 v.visit n_block
1303 v.addn
1304 v.indent -= 1
1305 v.addt
1306 v.add "end"
1307 end
1308
1309 if loop_label != null then
1310 v.adds
1311 v.visit loop_label
1312 end
1313 end
1314
1315 fun visit_loop_inline(v: PrettyPrinterVisitor) do
1316 var n_block = loop_block
1317 v.adds
1318
1319 if n_block isa ABlockExpr then
1320 if n_block.n_expr.is_empty then
1321 v.visit n_block.n_kwend
1322 else
1323 v.visit n_block.n_expr.first
1324 v.current_token = n_block.n_kwend
1325 v.skip
1326 end
1327 else
1328 v.visit n_block
1329 if v.current_token isa TKwend then v.skip
1330 end
1331
1332 if loop_label != null then
1333 v.adds
1334 v.visit loop_label
1335 end
1336 end
1337
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
1343 return true
1344 end
1345 end
1346
1347 redef class ALoopExpr
1348 super ALoopHelper
1349
1350 redef fun loop_block do return n_block
1351 redef fun loop_label do return n_label
1352
1353 redef fun accept_pretty_printer(v) do
1354 var can_inline = v.can_inline(self)
1355 v.visit n_kwloop
1356 if can_inline then visit_loop_inline v else visit_loop_block v
1357 end
1358 end
1359
1360 redef class AWhileExpr
1361 super ALoopHelper
1362
1363 redef fun loop_block do return n_block
1364 redef fun loop_label do return n_label
1365
1366 redef fun accept_pretty_printer(v) do
1367 var can_inline = v.can_inline(self)
1368 v.visit n_kwwhile
1369 v.adds
1370 v.visit n_expr
1371 v.adds
1372 v.visit n_kwdo
1373 if can_inline then visit_loop_inline v else visit_loop_block v
1374 end
1375 end
1376
1377 redef class ADoExpr
1378 super ALoopHelper
1379
1380 redef fun loop_block do return n_block
1381 redef fun loop_label do return n_label
1382
1383 redef fun accept_pretty_printer(v) do
1384 var can_inline = v.can_inline(self)
1385 v.visit n_kwdo
1386 if can_inline then visit_loop_inline v else visit_loop_block v
1387 end
1388 end
1389
1390 redef class AForExpr
1391 super ALoopHelper
1392
1393 redef fun loop_block do return n_block
1394 redef fun loop_label do return n_label
1395
1396 redef fun accept_pretty_printer(v) do
1397 var can_inline = v.can_inline(self)
1398 v.visit n_kwfor
1399 v.adds
1400
1401 for n_id in n_ids do
1402 v.visit n_id
1403 if n_id != n_ids.last then v.add ", "
1404 end
1405
1406 v.adds
1407 v.consume "in"
1408 v.adds
1409 v.visit n_expr
1410 v.adds
1411 v.visit n_kwdo
1412 if can_inline then visit_loop_inline v else visit_loop_block v
1413 end
1414 end
1415
1416 redef class ABreakExpr
1417 redef fun accept_pretty_printer(v) do
1418 v.visit n_kwbreak
1419
1420 if n_expr != null then
1421 v.adds
1422 v.visit n_expr
1423 end
1424
1425 if n_label != null then
1426 v.adds
1427 v.visit n_label
1428 end
1429 end
1430
1431 redef fun is_inlinable do return true
1432 end
1433
1434 redef class AContinueExpr
1435 redef fun accept_pretty_printer(v) do
1436 v.visit n_kwcontinue
1437
1438 if n_expr != null then
1439 v.adds
1440 v.visit n_expr
1441 end
1442
1443 if n_label != null then
1444 v.adds
1445 v.visit n_label
1446 end
1447 end
1448
1449 redef fun is_inlinable do return true
1450 end
1451
1452 # Calls
1453
1454 redef class ASendExpr
1455 redef fun is_inlinable do return true
1456 end
1457
1458 redef class ACallExpr
1459 redef fun accept_pretty_printer(v) do
1460 var can_inline = v.can_inline(self)
1461 v.visit_recv n_expr
1462
1463 if not n_expr isa AImplicitSelfExpr and not can_inline then
1464 v.addn
1465 v.addt
1466 v.addt
1467 end
1468
1469 v.visit n_id
1470
1471 if not n_args.n_exprs.is_empty then
1472 if is_stmt and n_args.n_exprs.length == 1 then
1473 v.adds
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
1477 else
1478 if v.current_token isa TOpar then
1479 v.consume "("
1480 else
1481 v.adds
1482 end
1483
1484 v.visit_list n_args.n_exprs
1485 if v.current_token isa TCpar then v.consume ")"
1486 end
1487 end
1488 end
1489
1490 # Is the call alone on its line?
1491 fun is_stmt: Bool do return parent isa ABlockExpr
1492 end
1493
1494 redef class ACallAssignExpr
1495 redef fun accept_pretty_printer(v) do
1496 v.visit_recv n_expr
1497 v.visit n_id
1498
1499 if not n_args.n_exprs.is_empty then
1500 v.consume "("
1501 v.visit_list n_args.n_exprs
1502 v.consume ")"
1503 end
1504
1505 v.adds
1506 v.consume "="
1507 v.adds
1508 v.visit n_value
1509 end
1510 end
1511
1512 redef class ACallReassignExpr
1513 redef fun accept_pretty_printer(v) do
1514 v.visit_recv n_expr
1515 v.visit n_id
1516
1517 if not n_args.n_exprs.is_empty then
1518 v.consume "("
1519 v.visit_list n_args.n_exprs
1520 v.consume ")"
1521 end
1522
1523 v.adds
1524 v.visit n_assign_op
1525 v.adds
1526 v.visit n_value
1527 end
1528 end
1529
1530 redef class ABraExpr
1531 redef fun accept_pretty_printer(v) do
1532 v.visit n_expr
1533
1534 if not n_args.n_exprs.is_empty then
1535 v.consume "["
1536 v.visit_list n_args.n_exprs
1537 v.consume "]"
1538 end
1539 end
1540 end
1541
1542 redef class ABraAssignExpr
1543 redef fun accept_pretty_printer(v) do
1544 v.visit n_expr
1545
1546 if not n_args.n_exprs.is_empty then
1547 v.consume "["
1548 v.visit_list n_args.n_exprs
1549 v.consume "]"
1550 end
1551
1552 v.adds
1553 v.visit n_assign
1554 v.adds
1555 v.visit n_value
1556 end
1557 end
1558
1559 redef class ABraReassignExpr
1560 redef fun accept_pretty_printer(v) do
1561 v.visit n_expr
1562
1563 if not n_args.n_exprs.is_empty then
1564 v.consume "["
1565 v.visit_list n_args.n_exprs
1566 v.consume "]"
1567 end
1568
1569 v.adds
1570 v.visit n_assign_op
1571 v.adds
1572 v.visit n_value
1573 end
1574 end
1575
1576 redef class AAssignMethid
1577 redef fun accept_pretty_printer(v) do
1578 v.visit n_id
1579 v.visit n_assign
1580 end
1581 end
1582
1583 redef class ABraMethid
1584 redef fun accept_pretty_printer(v) do
1585 v.visit n_obra
1586 v.visit n_cbra
1587 end
1588 end
1589
1590 redef class ABraassignMethid
1591 redef fun accept_pretty_printer(v) do
1592 v.visit n_obra
1593 v.visit n_cbra
1594 v.visit n_assign
1595 end
1596 end
1597
1598 redef class AInitExpr
1599 redef fun accept_pretty_printer(v) do
1600 if not n_expr isa AImplicitSelfExpr then
1601 v.visit n_expr
1602 v.consume "."
1603 end
1604
1605 v.visit n_kwinit
1606
1607 if not n_args.n_exprs.is_empty then
1608 v.consume "("
1609 v.visit_list n_args.n_exprs
1610 v.consume ")"
1611 end
1612 end
1613 end
1614
1615 redef class ANewExpr
1616 redef fun accept_pretty_printer(v) do
1617 var can_inline = v.can_inline(self)
1618 v.visit n_kwnew
1619 v.adds
1620 v.visit n_type
1621
1622 if n_id != null then
1623 v.consume "."
1624
1625 if not can_inline then
1626 v.addn
1627 v.addt
1628 v.addt
1629 end
1630
1631 v.visit n_id
1632 end
1633
1634 if not n_args.n_exprs.is_empty then
1635 v.consume "("
1636 v.visit_list n_args.n_exprs
1637 v.consume ")"
1638 end
1639 end
1640
1641 redef fun is_inlinable do return true
1642 end
1643
1644 # Attributes
1645
1646 redef class AAttrExpr
1647 redef fun accept_pretty_printer(v) do
1648 v.visit_recv n_expr
1649 v.visit n_id
1650 end
1651
1652 redef fun is_inlinable do return true
1653 end
1654
1655 redef class AAttrAssignExpr
1656 redef fun accept_pretty_printer(v) do
1657 v.visit_recv n_expr
1658 v.visit n_id
1659 v.adds
1660 v.visit n_assign
1661 v.adds
1662 v.visit n_value
1663 end
1664 end
1665
1666 redef class AAttrReassignExpr
1667 redef fun accept_pretty_printer(v) do
1668 v.visit_recv n_expr
1669 v.visit n_id
1670 v.adds
1671 v.visit n_assign_op
1672 v.adds
1673 v.visit n_value
1674 end
1675 end
1676
1677 # Exprs
1678
1679 redef class AVardeclExpr
1680 redef fun accept_pretty_printer(v) do
1681 v.visit n_kwvar
1682 v.adds
1683 v.visit n_id
1684
1685 if n_type != null then
1686 v.consume ":"
1687 v.adds
1688 v.visit n_type
1689 end
1690
1691 if n_expr != null then
1692 v.adds
1693 v.consume "="
1694 v.adds
1695 v.visit n_expr
1696 end
1697 end
1698
1699 redef fun is_inlinable do return true
1700 end
1701
1702 redef class AVarAssignExpr
1703 redef fun accept_pretty_printer(v) do
1704 v.visit n_id
1705 v.adds
1706 v.visit n_assign
1707 v.adds
1708 v.visit n_value
1709 end
1710 end
1711
1712 redef class AAssertExpr
1713 redef fun accept_pretty_printer(v) do
1714 var can_inline = v.can_inline(self)
1715 v.visit n_kwassert
1716
1717 if n_id != null then
1718 v.adds
1719 v.visit n_id
1720 v.consume ":"
1721 end
1722
1723 v.adds
1724 v.visit n_expr
1725 var n_else = self.n_else
1726
1727 if n_else != null then
1728 v.adds
1729 v.consume "else"
1730
1731 if can_inline then
1732 v.adds
1733 v.visit n_else
1734 else
1735 v.addn
1736
1737 if n_else isa ABlockExpr then
1738 v.indent += 1
1739 n_else.force_block = true
1740 v.visit n_else
1741 v.indent -= 1
1742 v.addt
1743 v.visit n_else.n_kwend
1744 else
1745 v.indent += 1
1746 v.addt
1747 v.visit n_else
1748 v.addn
1749 v.indent -= 1
1750 v.addt
1751 v.add "end"
1752 end
1753 end
1754 end
1755 end
1756
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
1760 return true
1761 end
1762 end
1763
1764 redef class AReturnExpr
1765 redef fun accept_pretty_printer(v) do
1766 v.visit n_kwreturn
1767
1768 if n_expr != null then
1769 v.adds
1770 v.visit n_expr
1771 end
1772 end
1773 end
1774
1775 redef class ASuperExpr
1776 redef fun accept_pretty_printer(v) do
1777 v.visit n_kwsuper
1778
1779 if not n_args.n_exprs.is_empty then
1780 if is_stmt and n_args.n_exprs.length == 1 then
1781 v.adds
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
1785 else
1786 if v.current_token isa TOpar then
1787 v.consume "("
1788 else
1789 v.adds
1790 end
1791
1792 v.visit_list n_args.n_exprs
1793 if v.current_token isa TCpar then v.consume ")"
1794 end
1795 end
1796 end
1797
1798 # Is the call alone on its line?
1799 fun is_stmt: Bool do return self.first_token.is_starting_line
1800
1801 redef fun is_inlinable do return true
1802 end
1803
1804 redef class AOnceExpr
1805 redef fun accept_pretty_printer(v) do
1806 v.visit n_kwonce
1807 v.adds
1808 v.visit n_expr
1809 end
1810
1811 redef fun is_inlinable do return true
1812 end
1813
1814 redef class AAbortExpr
1815 redef fun accept_pretty_printer(v) do v.visit n_kwabort
1816 redef fun is_inlinable do return true
1817 end
1818
1819 redef class ANotExpr
1820 redef fun accept_pretty_printer(v) do
1821 v.visit n_kwnot
1822 v.adds
1823 v.visit n_expr
1824 end
1825 end
1826
1827 redef class AAsCastExpr
1828 redef fun accept_pretty_printer(v) do
1829 v.visit n_expr
1830 v.consume "."
1831 v.visit n_kwas
1832 v.visit n_opar
1833 v.visit n_type
1834 v.visit n_cpar
1835 end
1836 end
1837
1838 redef class AAsNotnullExpr
1839 redef fun accept_pretty_printer(v) do
1840 v.visit n_expr
1841 v.consume "."
1842 v.visit n_kwas
1843 v.visit n_opar
1844 v.visit n_kwnot
1845 v.adds
1846 v.visit n_kwnull
1847 v.visit n_cpar
1848 end
1849 end
1850
1851 # Binops
1852
1853 # Used to factorize work on Or, And, Implies and Binop expressions.
1854 private class ABinOpHelper
1855 super AExpr
1856
1857 fun bin_expr1: AExpr is abstract
1858 fun bin_expr2: AExpr is abstract
1859
1860 # Operator string
1861 fun bin_op: String is abstract
1862
1863 redef fun accept_pretty_printer(v) do
1864 var can_inline = v.can_inline(self)
1865
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))
1870 then
1871 bin_expr1.force_block = true
1872 end
1873 end
1874
1875 v.visit bin_expr1
1876 v.adds
1877 v.consume bin_op
1878
1879 if can_inline then
1880 v.adds
1881 v.visit bin_expr2
1882 else
1883 v.addn
1884 v.addt
1885 v.addt
1886 v.visit bin_expr2
1887 end
1888 end
1889 end
1890
1891 redef class AAndExpr
1892 super ABinOpHelper
1893
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"
1897 end
1898
1899 redef class AOrExpr
1900 super ABinOpHelper
1901
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"
1905 end
1906
1907 redef class AImpliesExpr
1908 super ABinOpHelper
1909
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"
1913 end
1914
1915 redef class ABinopExpr
1916 super ABinOpHelper
1917
1918 redef fun bin_expr1 do return n_expr
1919 redef fun bin_expr2 do return n_expr2
1920 end
1921
1922 redef class AEqExpr
1923 redef fun bin_op do return "=="
1924 end
1925
1926 redef class AGeExpr
1927 redef fun bin_op do return ">="
1928 end
1929
1930 redef class AGgExpr
1931 redef fun bin_op do return ">>"
1932 end
1933
1934 redef class AGtExpr
1935 redef fun bin_op do return ">"
1936 end
1937
1938 redef class ALeExpr
1939 redef fun bin_op do return "<="
1940 end
1941
1942 redef class ALlExpr
1943 redef fun bin_op do return "<<"
1944 end
1945
1946 redef class ALtExpr
1947 redef fun bin_op do return "<"
1948 end
1949
1950 redef class AMinusExpr
1951 redef fun bin_op do return "-"
1952 end
1953
1954 redef class ANeExpr
1955 redef fun bin_op do return "!="
1956 end
1957
1958 redef class APercentExpr
1959 redef fun bin_op do return "%"
1960 end
1961
1962 redef class APlusExpr
1963 redef fun bin_op do return "+"
1964 end
1965
1966 redef class ASlashExpr
1967 redef fun bin_op do return "/"
1968 end
1969
1970 redef class AStarExpr
1971 redef fun bin_op do return "*"
1972 end
1973
1974 redef class AStarstarExpr
1975 redef fun bin_op do return "**"
1976 end
1977
1978 redef class AStarshipExpr
1979 redef fun bin_op do return "<=>"
1980 end
1981
1982 redef class AIsaExpr
1983 redef fun accept_pretty_printer(v) do
1984 v.visit n_expr
1985 v.adds
1986 v.consume "isa"
1987 v.adds
1988 v.visit n_type
1989 end
1990 end
1991
1992 redef class AOrElseExpr
1993 redef fun accept_pretty_printer(v) do
1994 v.visit n_expr
1995 v.adds
1996 v.consume "or"
1997 v.adds
1998 v.consume "else"
1999 v.adds
2000 v.visit n_expr2
2001 end
2002
2003 redef fun is_inlinable do return true
2004 end
2005
2006 # Syntax
2007
2008 redef class AUminusExpr
2009 redef fun accept_pretty_printer(v) do
2010 v.consume "-"
2011 v.visit n_expr
2012 end
2013 end
2014
2015 redef class ANullExpr
2016 redef fun accept_pretty_printer(v) do v.visit n_kwnull
2017 redef fun is_inlinable do return true
2018 end
2019
2020 redef class AParExpr
2021 redef fun accept_pretty_printer(v) do
2022 v.visit n_opar
2023 v.visit n_expr
2024 v.visit n_cpar
2025 end
2026 end
2027
2028 redef class AArrayExpr
2029 redef fun accept_pretty_printer(v) do
2030 v.consume "["
2031 v.visit_list n_exprs.n_exprs
2032 v.consume "]"
2033 end
2034 end
2035
2036 redef class ACrangeExpr
2037 redef fun accept_pretty_printer(v) do
2038 v.visit n_obra
2039 v.visit n_expr
2040 v.consume ".."
2041 v.visit n_expr2
2042 v.visit n_cbra
2043 end
2044 end
2045
2046 redef class AOrangeExpr
2047 redef fun accept_pretty_printer(v) do
2048 v.visit n_obra
2049 v.visit n_expr
2050 v.consume ".."
2051 v.visit n_expr2
2052 v.visit n_cbra
2053 end
2054 end
2055
2056 # Strings
2057
2058 redef class AStringFormExpr
2059 redef fun accept_pretty_printer(v) do
2060 var can_inline = v.can_inline(self)
2061
2062 if can_inline then
2063 v.visit n_string
2064 else
2065 var text = n_string.text
2066 var i = 0
2067
2068 while i < text.length do
2069 v.add text[i].to_s
2070
2071 if v.current_length >= v.max_size and i <= text.length - 3 then
2072 v.add "\" +"
2073 v.addn
2074 v.indent += 1
2075 v.addt
2076 v.indent -= 1
2077 v.add "\""
2078 end
2079
2080 i += 1
2081 end
2082
2083 v.current_token = n_string.next_token
2084 end
2085 end
2086 end
2087
2088 redef class ASuperstringExpr
2089 redef fun accept_pretty_printer(v) do
2090 for n_expr in n_exprs do v.visit n_expr
2091 end
2092
2093 redef fun must_be_inline do
2094 if super then return true
2095
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("\"\"\"")
2099 end
2100
2101 return false
2102 end
2103 end