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