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