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