src: remove some warnings and do some cleaning
[nit.git] / src / highlight.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 # Highliting of Nit AST
16 module highlight
17
18 import frontend
19 import html
20 import pipeline
21 import astutil
22
23 # Visitor used to produce a HTML tree based on a AST on a `Source`
24 class HighlightVisitor
25 # The root of the HTML hierarchy
26 var html = new HTMLTag("span")
27
28 # Is the HTML include a nested `<span class"{type_of_node}">` element for each `ANode` of the AST?
29 # Used to have a really huge and verbose HTML (mainly for debug)
30 var with_ast = false is writable
31
32 # The first line to generate, null if start at the first line
33 var first_line: nullable Int = null is writable
34
35 # The last line to generate, null if finish at the last line
36 var last_line: nullable Int = null is writable
37
38 init
39 do
40 html.add_class("nitcode")
41 end
42
43 fun enter_visit(n: ANode)
44 do
45 n.parentize_tokens
46 var s = n.location.file
47 htmlize(s.first_token.as(not null), s.last_token.as(not null))
48 end
49
50 # Produce HTML between two tokens
51 protected fun htmlize(first_token, last_token: Token)
52 do
53 var stack2 = new Array[HTMLTag]
54 var stack = new Array[Prod]
55 var line = 0
56 var c: nullable Token = first_token
57 var hv = new HighlightVisitor
58 while c != null do
59 var starting
60
61 # Handle start of line
62 var cline = c.location.line_start
63 if cline != line then
64 # Handle starting block productions,
65 # Because c could be a detached token, get prods in
66 # the first AST token
67 var c0 = c.first_token_in_line
68 starting = null
69 if c0 != null then starting = c0.starting_prods
70 if starting != null then for p in starting do
71 if not p.is_block then continue
72 var tag = p.make_tag(hv)
73 if tag == null then continue
74 tag.add_class("foldable")
75 var infobox = p.infobox(hv)
76 if infobox != null then tag.attach_infobox(infobox)
77 stack2.add(html)
78 html.add tag
79 html = tag
80 stack.add(p)
81 end
82
83 # Add a div for the whole line
84 var tag = new HTMLTag("span")
85 tag.attrs["id"] = "L{cline}"
86 tag.classes.add "line"
87 stack2.add(html)
88 html.add tag
89 html = tag
90 line = cline
91 end
92
93 # Add the blank, verbatim
94 html.add_raw_html c.blank_before
95
96 # Handle starting span production
97 starting = c.starting_prods
98 if starting != null then for p in starting do
99 if not p.is_span then continue
100 var tag = p.make_tag(hv)
101 if tag == null then continue
102 var infobox = p.infobox(hv)
103 if infobox != null then tag.attach_infobox(infobox)
104 stack2.add(html)
105 html.add tag
106 html = tag
107 stack.add(p)
108 end
109
110 # Add the token
111 if c isa TEol then
112 html.append "\n"
113 else
114 var tag = c.make_tag(hv)
115 var pa = c.parent
116 var infobox = null
117 if c isa TId or c isa TClassid or c isa TAttrid or c isa TokenLiteral or c isa TokenOperator then
118 assert c != null
119 if pa != null then infobox = pa.decorate_tag(hv, tag, c)
120 else if c isa TComment and pa isa ADoc then
121 infobox = pa.decorate_tag(hv, tag, c)
122 end
123 if infobox != null then tag.attach_infobox(infobox)
124 html.add tag
125 end
126
127 # Handle ending span productions
128 var ending = c.ending_prods
129 if ending != null then for p in ending do
130 if not p.is_span then continue
131 if stack.is_empty or p != stack.last then continue
132 stack.pop
133 html = stack2.pop
134 end
135
136 # Handle end of line and end of file
137 var n = c.next_token
138 if c == last_token then n = null
139 if n == null or n.location.line_start != line then
140 # closes the line div
141 html = stack2.pop
142
143 # close the block production divs
144 var c0 = c.last_token_in_line
145 ending = null
146 if c0 != null then ending = c0.ending_prods
147 if ending != null then for p in ending do
148 if not p.is_block then continue
149 if stack.is_empty or p != stack.last then continue
150 stack.pop
151 html = stack2.pop
152 end
153 end
154
155 c = n
156 end
157 assert stack.is_empty
158 assert stack2.is_empty
159 end
160
161 # Return a default CSS content related to CSS classes used in the `html` tree.
162 # Could be inlined in the `.html` file of saved as a specific `.css` file.
163 fun css_content: String
164 do
165 return """
166 .nitcode a { color: inherit; cursor:pointer; }
167 .nitcode .popupable:hover { text-decoration: underline; cursor:help; } /* underline titles */
168 pre.nitcode .foldable { display: block } /* for block productions*/
169 pre.nitcode .line{ display: block } /* for lines */
170 pre.nitcode .line:hover{ background-color: #FFFFE0; } /* current line */
171 .nitcode :target { background-color: #FFF3C2 } /* target highlight*/
172 /* lexical raw tokens. independent of usage or semantic: */
173 .nitcode .nc_c { color: gray; font-style: italic; } /* comment */
174 .nitcode .nc_d { color: #3D8127; font-style: italic; } /* documentation comments */
175 .nitcode .nc_k { font-weight: bold; } /* keyword */
176 .nitcode .nc_o {} /* operator */
177 .nitcode .nc_i {} /* standard identifier */
178 .nitcode .nc_t { color: #445588; font-weight: bold; } /* type/class identifier */
179 .nitcode .nc_a { color: #445588; font-style: italic; } /* old style attribute identifier */
180 .nitcode .nc_l { color: #009999; } /* char and number literal */
181 .nitcode .nc_s { color: #8F1546; } /* string literal */
182 /* syntactic token usage. added because of their position in the AST */
183 .nitcode .nc_ast { color: blue; } /* assert label */
184 .nitcode .nc_la { color: blue; } /* break/continue label */
185 .nitcode .nc_m { color: #445588; } /* module name */
186 /* syntactic groups */
187 .nitcode .nc_def { font-weight: bold; color: blue; } /* name used in a definition */
188 .nitcode .nc_def.nc_a { color: blue; } /* name used in a attribute definition */
189 .nitcode .nc_def.nc_t { color: blue; } /* name used in a class or vt definition */
190 .nitcode .nc_ss { color: #9E6BEB; } /* superstrings */
191 .nitcode .nc_cdef {} /* A whole class definition */
192 .nitcode .nc_pdef {} /* A whole property definition */
193 /* semantic token usage */
194 .nitcode .nc_v { font-style: italic; } /* local variable or parameter */
195 .nitcode .nc_vt { font-style: italic; } /* virtual type or formal type */
196
197 .nitcode .nc_error { border: 1px red solid;} /* not used */
198 .popover { max-width: 800px !important; }
199 """
200 end
201
202 # Additional content to inject in the <head> tag
203 # Note: does not include `css_content`; handle it yourself.
204 fun head_content: String
205 do
206 return """<link rel="stylesheet" href="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/css/bootstrap.min.css">\n"""
207 end
208
209 # Additional content to inject just before the closing </body> tag
210 fun foot_content: String
211 do
212 return """
213 <script src="http://code.jquery.com/jquery-1.11.0.min.js"></script>
214 <script src="http://netdna.bootstrapcdn.com/bootstrap/3.1.1/js/bootstrap.min.js"></script>
215 <script>$(".popupable").popover({html:true, placement:'top'})/*initialize bootstrap popover*/</script>"""
216 end
217 end
218
219 redef class HTMLTag
220 # Attach the infobox to the node by using BootStrap popover
221 fun attach_infobox(infobox: HInfoBox)
222 do
223 classes.add("popupable")
224 attrs["title"] = infobox.title
225 var href = infobox.href
226 if href != null then
227 attrs["data-title"] = """<a href="{{{href}}}">{{{infobox.title}}}</a>"""
228 end
229 attrs["data-content"] = infobox.content.write_to_string
230 attrs["data-toggle"] = "popover"
231 end
232 end
233
234
235 # A generic information container that can be used to decorate AST entities
236 class HInfoBox
237 # The visitor used for contextualisation, if needed
238 var visitor: HighlightVisitor
239
240 # A short title for the AST element
241 var title: String
242
243 # The primary link where the entity points
244 # null if no link
245 var href: nullable String = null
246
247 # The content of the popuped infobox
248 var content = new HTMLTag("div")
249
250 # Append a new field in the popuped infobox
251 fun new_field(title: String): HTMLTag
252 do
253 content.open("b").text(title)
254 content.append(" ")
255 var res = content.open("span")
256 content.open("br")
257 return res
258 end
259
260 # Append a new dropdown in the popuped content
261 fun new_dropdown(title, text: String): HTMLTag
262 do
263 content.add_raw_html """<div class="dropdown"> <a data-toggle="dropdown" href="#"><b>"""
264 content.append(title)
265 content.add_raw_html "</b> "
266 content.append(text)
267 content.add_raw_html """<span class="caret"></span></a>"""
268 var res = content.open("ul").add_class("dropdown-menu").attr("role", "menu").attr("aria-labelledby", "dLabel")
269 content.add_raw_html "</div>"
270 return res
271 end
272 end
273
274 ##
275
276 # Model entity or whatever that can produce an infobox
277 interface HInfoBoxable
278 # An new infobox documenting the entity
279 fun infobox(v: HighlightVisitor): HInfoBox is abstract
280
281 # A human-readable hyper-text for the entity
282 fun linkto: HTMLTag is abstract
283 end
284
285 redef class MDoc
286 # Append an entry for the doc in the given infobox
287 fun fill_infobox(res: HInfoBox)
288 do
289 if content.length < 2 then
290 res.new_field("doc").text(content.first)
291 return
292 end
293 var c = res.new_dropdown("doc", content.first)
294 for x in content.iterator.skip_head(1) do
295 c.append x
296 c.add_raw_html "<br>"
297 end
298 end
299 end
300
301 redef class MEntity
302 super HInfoBoxable
303 end
304
305 redef class MModule
306 redef fun infobox(v)
307 do
308 var res = new HInfoBox(v, "module {name}")
309 res.href = href
310 res.new_field("module").add(linkto)
311 var mdoc = self.mdoc
312 if mdoc != null then mdoc.fill_infobox(res)
313 if in_importation.greaters.length > 1 then
314 var c = res.new_dropdown("imports", "{in_importation.greaters.length-1} modules")
315 for x in in_importation.greaters do
316 if x == self then continue
317 c.open("li").add x.linkto
318 end
319 end
320 return res
321 end
322
323 fun href: String
324 do
325 return name + ".html"
326 end
327
328 redef fun linkto do return linkto_text(name)
329
330 # Link to the entitiy with a specific text
331 fun linkto_text(text: String): HTMLTag
332 do
333 return (new HTMLTag("a")).attr("href", href).text(text)
334 end
335 end
336
337 redef class MClassDef
338 redef fun infobox(v)
339 do
340 var res = new HInfoBox(v, "class {mclass.name}")
341 res.href = href
342 if is_intro then
343 res.new_field("class").text(mclass.name)
344 else
345 res.new_field("redef class").text(mclass.name)
346 res.new_field("intro").add mclass.intro.linkto_text("in {mclass.intro.mmodule.to_s}")
347 end
348 var mdoc = self.mdoc
349 if mdoc == null then mdoc = mclass.intro.mdoc
350 if mdoc != null then mdoc.fill_infobox(res)
351
352 if in_hierarchy.greaters.length > 1 then
353 var c = res.new_dropdown("hier", "super-classes")
354 for x in in_hierarchy.greaters do
355 if x == self then continue
356 if not x.is_intro then continue
357 c.open("li").add x.linkto
358 end
359 end
360 if in_hierarchy.smallers.length > 1 then
361 var c = res.new_dropdown("hier", "sub-classes")
362 for x in in_hierarchy.smallers do
363 if x == self then continue
364 if not x.is_intro then continue
365 c.open("li").add x.linkto
366 end
367 end
368 if mclass.mclassdefs.length > 1 then
369 var c = res.new_dropdown("redefs", "refinements")
370 for x in mclass.mclassdefs do
371 if x == self then continue
372 c.open("li").add x.linkto_text("in {x.mmodule}")
373 end
374 end
375 return res
376 end
377
378 fun href: String
379 do
380 return mmodule.href + "#" + to_s
381 end
382
383 redef fun linkto do return linkto_text(mclass.name)
384
385 # Link to the entitiy with a specific text
386 fun linkto_text(text: String): HTMLTag
387 do
388 return (new HTMLTag("a")).attr("href", href).text(text)
389 end
390 end
391
392 redef class MPropDef
393 redef fun infobox(v)
394 do
395 var res = new HInfoBox(v, to_s)
396 res.href = href
397 if self isa MMethodDef then
398 res.new_field("fun").append(mproperty.name).add msignature.linkto
399 else if self isa MAttributeDef then
400 res.new_field("fun").append(mproperty.name).add static_mtype.linkto
401 else if self isa MVirtualTypeDef then
402 res.new_field("add").append(mproperty.name).add bound.linkto
403 else
404 res.new_field("wat?").append(mproperty.name)
405 end
406
407 if is_intro then
408 else
409 res.new_field("intro").add mproperty.intro.linkto_text("in {mproperty.intro.mclassdef}")
410 end
411 var mdoc = self.mdoc
412 if mdoc == null then mdoc = mproperty.intro.mdoc
413 if mdoc != null then mdoc.fill_infobox(res)
414 if mproperty.mpropdefs.length > 1 then
415 var c = res.new_dropdown("redef", "redefinitions")
416 for x in mproperty.mpropdefs do
417 c.open("li").add x.linkto_text("in {x.mclassdef}")
418 end
419 end
420
421 return res
422 end
423
424 fun href: String
425 do
426 return self.mclassdef.mmodule.href + "#" + self.to_s
427 end
428
429 redef fun linkto do return linkto_text(mproperty.name)
430
431 # Link to the entitiy with a specific text
432 fun linkto_text(text: String): HTMLTag
433 do
434 return (new HTMLTag("a")).attr("href", href).text(text)
435 end
436 end
437
438 redef class MClassType
439 redef fun infobox(v)
440 do
441 var res = new HInfoBox(v, to_s)
442 res.href = mclass.intro.href
443 res.new_field("class").add mclass.intro.linkto
444 var mdoc = mclass.mdoc
445 if mdoc == null then mdoc = mclass.intro.mdoc
446 if mdoc != null then mdoc.fill_infobox(res)
447 return res
448 end
449 redef fun linkto
450 do
451 return mclass.intro.linkto
452 end
453 end
454 redef class MVirtualType
455 redef fun infobox(v)
456 do
457 var res = new HInfoBox(v, to_s)
458 res.href = mproperty.intro.href
459 var p = mproperty
460 var pd = p.intro
461 res.new_field("virtual type").add pd.linkto
462 var mdoc = pd.mdoc
463 if mdoc != null then mdoc.fill_infobox(res)
464 return res
465 end
466 redef fun linkto
467 do
468 return mproperty.intro.linkto
469 end
470 end
471 redef class MParameterType
472 redef fun infobox(v)
473 do
474 var res = new HInfoBox(v, to_s)
475 res.new_field("parameter type").append("{name} from class ").add mclass.intro.linkto
476 return res
477 end
478 redef fun linkto
479 do
480 return (new HTMLTag("span")).text(name)
481 end
482 end
483
484 redef class MNullableType
485 redef fun infobox(v)
486 do
487 return mtype.infobox(v)
488 end
489 redef fun linkto
490 do
491 var res = new HTMLTag("span")
492 res.append("nullable ").add(mtype.linkto)
493 return res
494 end
495 end
496
497 redef class MSignature
498 redef fun linkto
499 do
500 var res = new HTMLTag("span")
501 var first = true
502 if not mparameters.is_empty then
503 res.append "("
504 for p in mparameters do
505 if first then
506 first = false
507 else
508 res.append ", "
509 end
510 res.append p.name
511 res.append ": "
512 res.add p.mtype.linkto
513 end
514 res.append ")"
515 end
516 var ret = return_mtype
517 if ret != null then
518 res.append ": "
519 res.add ret.linkto
520 end
521 return res
522 end
523 end
524
525 redef class CallSite
526 super HInfoBoxable
527 redef fun infobox(v)
528 do
529 var res = new HInfoBox(v, "call {mpropdef}")
530 res.href = mpropdef.href
531 res.new_field("call").add(mpropdef.linkto).add(msignature.linkto)
532 if mpropdef.is_intro then
533 else
534 res.new_field("intro").add mproperty.intro.linkto_text("in {mproperty.intro.mclassdef}")
535 end
536 var mdoc = mpropdef.mdoc
537 if mdoc == null then mdoc = mproperty.intro.mdoc
538 if mdoc != null then mdoc.fill_infobox(res)
539
540 return res
541 end
542 redef fun linkto
543 do
544 return mpropdef.linkto
545 end
546 end
547
548 redef class Variable
549 super HInfoBoxable
550 redef fun infobox(v)
551 do
552 var declared_type = self.declared_type
553 if declared_type == null then
554 var res = new HInfoBox(v, "{name}")
555 res.new_field("local var").append("{name}")
556 return res
557 end
558 var res = new HInfoBox(v, "{name}: {declared_type}")
559 res.new_field("local var").append("{name}:").add(declared_type.linkto)
560 return res
561 end
562 redef fun linkto
563 do
564 return (new HTMLTag("span")).text(name)
565 end
566 end
567
568
569 ##
570
571 redef class ANode
572 # Optionally creates a tag that encapsulate the AST element on HTML rendering
573 protected fun make_tag(v: HighlightVisitor): nullable HTMLTag do return null
574
575 # Add aditionnal information on a child-token and return an additionnal HInfoBox on it
576 protected fun decorate_tag(v: HighlightVisitor, res: HTMLTag, token: Token): nullable HInfoBox
577 do
578 #debug("no decoration for {token.inspect}")
579 #res.add_class("nc_error")
580 return null
581 end
582
583 # Return a optional infobox
584 fun infobox(v: HighlightVisitor): nullable HInfoBox do return null
585 end
586
587 redef class AStdClassdef
588 redef fun make_tag(v)
589 do
590 var res = new HTMLTag("span")
591 res.add_class("nc_cdef")
592 var md = mclassdef
593 if md != null then res.attr("id", md.to_s)
594 return res
595 end
596 redef fun decorate_tag(v, res, token)
597 do
598 res.add_class("nc_def")
599
600 var md = mclassdef
601 if md == null then return null
602 return md.infobox(v)
603 end
604 end
605 redef class APropdef
606 redef fun make_tag(v)
607 do
608 var res = new HTMLTag("span")
609 res.add_class("nc_pdef")
610 var mpd
611 mpd = mpropdef
612 if mpd != null then
613 #res.add(tag(mpd))
614 res.attr("id", mpd.to_s)
615 end
616 if self isa AAttrPropdef then
617 mpd = mreadpropdef
618 if mpd != null then res.add(tag(mpd))
619 mpd = mwritepropdef
620 if mpd != null then res.add(tag(mpd))
621 end
622 return res
623 end
624
625 private fun tag(mpd: MPropDef): HTMLTag
626 do
627 var a = new HTMLTag("a")
628 a.attr("id", mpd.to_s)
629 return a
630 end
631 end
632
633 redef class Token
634 # Produce an HTMLTag with the correct contents and CSS classes
635 # Subclasses can redefine it to decorate the tag
636 redef fun make_tag(v: HighlightVisitor): HTMLTag
637 do
638 var res = new HTMLTag("span")
639 res.text(text)
640 return res
641 end
642 end
643
644 redef class TokenKeyword
645 redef fun make_tag(v)
646 do
647 var res = super
648 res.add_class("nc_k")
649 return res
650 end
651 end
652 redef class TokenOperator
653 redef fun make_tag(v)
654 do
655 var res = super
656 var p = parent
657 if p != null then p.decorate_tag(v, res, self)
658 res.add_class("nc_o")
659 return res
660 end
661 end
662
663 redef class AVarFormExpr
664 redef fun decorate_tag(v, res, token)
665 do
666 var variable = self.variable
667 if variable == null then return null
668 res.add_class("nc_v")
669 return variable.infobox(v)
670 end
671 end
672
673 redef class AVardeclExpr
674 redef fun decorate_tag(v, res, token)
675 do
676 var variable = self.variable
677 if variable == null then return null
678 res.add_class("nc_v")
679 return variable.infobox(v)
680 end
681 end
682
683 redef class AForExpr
684 redef fun decorate_tag(v, res, token)
685 do
686 if not token isa TId then return null
687 var vs = variables
688 if vs == null then return null
689 res.add_class("nc_v")
690 var idx = n_ids.index_of(token)
691 var variable = vs[idx]
692 return variable.infobox(v)
693 end
694 end
695
696 redef class AParam
697 redef fun decorate_tag(v, res, token)
698 do
699 var mp = mparameter
700 if mp == null then return null
701 var variable = self.variable
702 if variable == null then return null
703 res.add_class("nc_v")
704 return variable.infobox(v)
705 end
706 end
707
708 redef class AAssertExpr
709 redef fun decorate_tag(v, res, token)
710 do
711 res.add_class("nc_ast")
712 return null
713 end
714 end
715
716 redef class ALabel
717 redef fun decorate_tag(v, res, token)
718 do
719 res.add_class("nc_la")
720 return null
721 end
722 end
723
724 redef class ASendExpr
725 redef fun decorate_tag(v, res, token)
726 do
727 if callsite == null then return null
728 return callsite.infobox(v)
729 end
730 end
731
732 redef class ANewExpr
733 redef fun decorate_tag(v, res, token)
734 do
735 if callsite == null then return null
736 return callsite.infobox(v)
737 end
738 end
739
740 redef class AAssignOp
741 redef fun decorate_tag(v, res, token)
742 do
743 var p = parent
744 assert p isa AReassignFormExpr
745
746 var callsite = p.reassign_callsite
747 if callsite == null then return null
748 return callsite.infobox(v)
749 end
750 end
751
752 redef class AModuleName
753 redef fun decorate_tag(v, res, token)
754 do
755 return parent.decorate_tag(v, res, token)
756 end
757 end
758
759 redef class AModuledecl
760 redef fun decorate_tag(v, res, token)
761 do
762 res.add_class("nc_def")
763 res.add_class("nc_m")
764 var p = parent
765 assert p isa AModule
766 var mm = p.mmodule
767 if mm == null then return null
768 return mm.infobox(v)
769 end
770 end
771
772 redef class AStdImport
773 redef fun decorate_tag(v, res, token)
774 do
775 res.add_class("nc_m")
776 var mm = mmodule
777 if mm == null then return null
778 return mm.infobox(v)
779 end
780 end
781 redef class AAttrPropdef
782 redef fun decorate_tag(v, res, token)
783 do
784 res.add_class("nc_def")
785 var mpd: nullable MPropDef
786 mpd = mreadpropdef
787 if mpd == null then mpd = mpropdef
788 if mpd == null then return null
789 return mpd.infobox(v)
790 end
791 end
792
793 redef class TId
794 redef fun make_tag(v)
795 do
796 var res = super
797 var p = parent
798 if p != null then p.decorate_tag(v, res, self)
799 res.add_class("nc_i")
800 return res
801 end
802 end
803 redef class AMethid
804 redef fun make_tag(v)
805 do
806 var res = new HTMLTag("span")
807 res.add_class("nc_def")
808 return res
809 end
810 redef fun decorate_tag(v, res, token)
811 do
812 return null
813 # nothing to decorate
814 end
815 redef fun infobox(v)
816 do
817 var p = parent
818 if not p isa AMethPropdef then return null
819 var mpd = p.mpropdef
820 if mpd == null then return null
821 return mpd.infobox(v)
822 end
823 end
824 redef class TAttrid
825 redef fun make_tag(v)
826 do
827 var res = super
828 var p = parent
829 if p != null then p.decorate_tag(v, res, self)
830 res.add_class("nc_a")
831 return res
832 end
833 end
834 redef class AAttrFormExpr
835 redef fun decorate_tag(v, res, token)
836 do
837 var p = mproperty
838 if p == null then return null
839 return p.intro.infobox(v)
840 end
841 end
842 redef class TClassid
843 redef fun make_tag(v)
844 do
845 var res = super
846 var p = parent
847 if p != null then p.decorate_tag(v, res, self)
848 res.add_class("nc_t")
849 return res
850 end
851 end
852 redef class AType
853 redef fun decorate_tag(v, res, token)
854 do
855 var mt = mtype
856 if mt == null then return null
857 mt = mt.as_notnullable
858 if mt isa MVirtualType or mt isa MParameterType then
859 res.add_class("nc_vt")
860 end
861 return mt.infobox(v)
862 end
863 end
864 redef class AFormaldef
865 redef fun decorate_tag(v, res, token)
866 do
867 res.add_class("nc_vt")
868 if mtype == null then return null
869 return mtype.infobox(v)
870 end
871 end
872 redef class ATypePropdef
873 redef fun decorate_tag(v, res, token)
874 do
875 res.add_class("nc_def")
876 var md = mpropdef
877 if md == null then return null
878 return md.infobox(v)
879 end
880 end
881 redef class TComment
882 redef fun make_tag(v)
883 do
884 var res = super
885 if not parent isa ADoc then
886 res.add_class("nc_c")
887 end
888 return res
889 end
890 end
891 redef class ADoc
892 redef fun make_tag(v)
893 do
894 var res = new HTMLTag("span")
895 res.add_class("nc_d")
896 return res
897 end
898 end
899 redef class TokenLiteral
900 redef fun make_tag(v)
901 do
902 var res = super
903 res.add_class("nc_l")
904 var p = parent
905 if p != null then p.decorate_tag(v, res, self)
906 return res
907 end
908 end
909 redef class ASuperstringExpr
910 redef fun make_tag(v)
911 do
912 var res = new HTMLTag("span")
913 res.add_class("nc_ss")
914 return res
915 end
916 end
917 redef class AStringFormExpr
918 redef fun decorate_tag(v, res, token)
919 do
920 # Workaround to tag strings
921 res.classes.remove("nc_l")
922 res.add_class("nc_s")
923 return null
924 end
925 end
926 redef class AExpr
927 redef fun decorate_tag(v, res, token)
928 do
929 var t = mtype
930 if t == null then return null
931 return t.infobox(v)
932 end
933 end