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