~emersion/gyosu

ref: bcc2eda9ba1b7292700f6ac32190f9ab6f89c05a gyosu/comment.go -rw-r--r-- 2.2 KiB
bcc2eda9Simon Ser ci: add .build.yml 4 months ago
                                                                                
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
package main

import (
	"strings"
	"unicode"

	"modernc.org/cc/v3"
)

func cutComment(s string) (string, string) {
	start := strings.Index(s, "/*")
	if start < 0 {
		return "", ""
	}

	j := strings.Index(s[start:], "*/")
	if j < 0 {
		return "", ""
	}
	end := start + j + len("*/")

	return s[start:end], s[end:]
}

// parseParagraph parses a raw paragraph text into inline elements. The
// recognized elements are:
//
//     struct foo
//     enum foo
//     union foo
//     foo()
func parseParagraph(raw string) paragraph {
	var p paragraph
	for len(raw) > 0 {
		var word string
		word, raw = nextWord(raw)

		if len(raw) >= 2 && raw[0] == ' ' && isDeclKind(word) {
			var name string
			name, raw = nextWord(raw[1:])
			p = append(p, inline{
				Type:  inlineSymbol,
				Value: name,
				Kind:  declKind(word),
			})
			continue
		}

		if len(raw) >= 2 && raw[:2] == "()" {
			p = append(p, inline{
				Type:  inlineSymbol,
				Value: word,
				Kind:  declFunc,
			})
			raw = raw[2:]
			continue
		}

		p = append(p, inline{Type: inlineText, Value: word})
	}

	return p
}

func nextWord(s string) (word string, next string) {
	for i, ch := range s {
		if isWordBoundary(ch) {
			if i == 0 {
				return s[:1], s[1:]
			} else {
				return s[:i], s[i:]
			}
		}
	}
	return s, ""
}

func isDeclKind(s string) bool {
	switch s {
	case "struct", "enum", "union":
		return true
	default:
		return false
	}
}

func isWordBoundary(ch rune) bool {
	return !unicode.IsLetter(ch) && !unicode.IsDigit(ch) && ch != '_'
}

func extractDocComment(tok cc.Token) []paragraph {
	// Pick the last comment
	rest := tok.Sep.String()
	var comment string
	for {
		nextComment, nextRest := cutComment(rest)
		if nextComment == "" {
			break
		}
		comment, rest = nextComment, nextRest
	}

	if comment == "" || rest != "\n" {
		return nil
	}

	s := comment
	s = strings.TrimPrefix(strings.TrimPrefix(s, "/*"), "*")
	s = strings.TrimSuffix(s, "*/")
	s = strings.TrimSpace(s)

	lines := strings.Split(s, "\n")
	for i, l := range lines {
		l = strings.TrimPrefix(strings.TrimSpace(l), "* ")
		if l == "*" {
			l = ""
		}
		lines[i] = l
	}

	doc := strings.Join(lines, "\n")
	var out []paragraph
	for _, raw := range strings.Split(doc, "\n\n") {
		out = append(out, parseParagraph(raw))
	}
	return out
}