...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24 package proto
25
26 import (
27 "strings"
28 "text/scanner"
29 )
30
31
32 type Comment struct {
33 Position scanner.Position
34
35 Lines []string
36 Cstyle bool
37 ExtraSlash bool
38 }
39
40
41 func newComment(pos scanner.Position, lit string) *Comment {
42 extraSlash := strings.HasPrefix(lit, "///")
43 isCstyle := strings.HasPrefix(lit, "/*") && strings.HasSuffix(lit, "*/")
44 var lines []string
45 if isCstyle {
46 withoutMarkers := strings.TrimRight(strings.TrimLeft(lit, "/*"), "*/")
47 lines = strings.Split(withoutMarkers, "\n")
48 } else {
49 lines = strings.Split(strings.TrimLeft(lit, "/"), "\n")
50 }
51 return &Comment{Position: pos, Lines: lines, Cstyle: isCstyle, ExtraSlash: extraSlash}
52 }
53
54 type inlineComment struct {
55 line string
56 extraSlash bool
57 }
58
59
60 func (c *Comment) Accept(v Visitor) {
61 v.VisitComment(c)
62 }
63
64
65 func (c *Comment) Merge(other *Comment) {
66 c.Lines = append(c.Lines, other.Lines...)
67 c.Cstyle = c.Cstyle || other.Cstyle
68 }
69
70 func (c Comment) hasTextOnLine(line int) bool {
71 if len(c.Lines) == 0 {
72 return false
73 }
74 return c.Position.Line <= line && line <= c.Position.Line+len(c.Lines)-1
75 }
76
77
78 func (c Comment) Message() string {
79 if len(c.Lines) == 0 {
80 return ""
81 }
82 return c.Lines[0]
83 }
84
85
86 type commentInliner interface {
87 inlineComment(c *Comment)
88 }
89
90
91 func maybeScanInlineComment(p *Parser, c elementContainer) {
92 currentPos := p.scanner.Position
93
94 pos, tok, lit := p.next()
95 esize := len(c.elements())
96
97 if tCOMMENT == tok && pos.Line == currentPos.Line && esize > 0 {
98
99 last := c.elements()[esize-1]
100 if inliner, ok := last.(commentInliner); ok {
101
102 inliner.inlineComment(newComment(pos, lit))
103 }
104 } else {
105 p.nextPut(pos, tok, lit)
106 }
107 }
108
109
110 func takeLastCommentIfEndsOnLine(list []Visitee, line int) (*Comment, []Visitee) {
111 if len(list) == 0 {
112 return nil, list
113 }
114 if last, ok := list[len(list)-1].(*Comment); ok && last.hasTextOnLine(line) {
115 return last, list[:len(list)-1]
116 }
117 return nil, list
118 }
119
120
121 func mergeOrReturnComment(elements []Visitee, lit string, pos scanner.Position) *Comment {
122 com := newComment(pos, lit)
123 esize := len(elements)
124 if esize == 0 {
125 return com
126 }
127
128 last, ok := elements[esize-1].(*Comment)
129 if !ok {
130 return com
131 }
132
133 if last.Cstyle {
134 return com
135 }
136
137
138 if !last.hasTextOnLine(pos.Line - 1) {
139 return com
140 }
141 last.Merge(com)
142 return nil
143 }
144
145
146 func (c *Comment) parent(Visitee) {}
147
148
149 func consumeCommentFor(p *Parser, e elementContainer) {
150 pos, tok, lit := p.next()
151 if tok == tCOMMENT {
152 if com := mergeOrReturnComment(e.elements(), lit, pos); com != nil {
153 e.addElement(com)
154 }
155 consumeCommentFor(p, e)
156 } else {
157 p.nextPut(pos, tok, lit)
158 }
159 }
160
View as plain text