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