forked from go-llvm/llgo
/
attribute.go
122 lines (111 loc) · 3.19 KB
/
attribute.go
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
// Copyright 2012 Andrew Wilkins.
// Use of this source code is governed by an MIT-style
// license that can be found in the LICENSE file.
package llgo
import (
"github.com/axw/gollvm/llvm"
"github.com/axw/llgo/types"
"go/ast"
"strings"
)
const AttributeCommentPrefix = "#llgo "
// Atribute represents an attribute associated with a
// global variable or function.
type Attribute interface {
Apply(Value)
}
// parseAttribute parses zero or more #llgo comment attributes associated with
// a global variable or function. The comment group provided will be processed
// one line at a time using parseAttribute.
func parseAttributes(doc *ast.CommentGroup) []Attribute {
var attributes []Attribute
if doc == nil {
return attributes
}
for _, comment := range doc.List {
text := comment.Text[2:]
if strings.HasPrefix(comment.Text, "/*") {
text = text[:len(text)-2]
}
attr := parseAttribute(strings.TrimSpace(text))
if attr != nil {
attributes = append(attributes, attr)
}
}
return attributes
}
// parseAttribute parses a single #llgo comment attribute associated with
// a global variable or function. The string provided will be parsed
// if it begins with AttributeCommentPrefix, otherwise nil is returned.
func parseAttribute(line string) Attribute {
if !strings.HasPrefix(line, AttributeCommentPrefix) {
return nil
}
line = strings.TrimSpace(line[len(AttributeCommentPrefix):])
colon := strings.IndexRune(line, ':')
key, value := line[:colon], line[colon+1:]
switch key {
case "linkage":
return parseLinkageAttribute(value)
case "name":
return nameAttribute(strings.TrimSpace(value))
default:
// FIXME decide what to do here. return error? log warning?
panic("unknown attribute key: " + key)
}
return nil
}
type linkageAttribute llvm.Linkage
func (a linkageAttribute) Apply(v Value) {
global := v.(*LLVMValue).pointer.value
global.SetLinkage(llvm.Linkage(a))
}
func parseLinkageAttribute(value string) linkageAttribute {
var result linkageAttribute
value = strings.Replace(value, ",", " ", -1)
for _, field := range strings.Fields(value) {
switch strings.ToLower(field) {
case "private":
result |= llvm.PrivateLinkage
case "linker_private":
result |= llvm.LinkerPrivateLinkage
case "linker_private_weak":
result |= llvm.LinkerPrivateWeakLinkage
case "internal":
result |= llvm.InternalLinkage
case "available_externally":
result |= llvm.AvailableExternallyLinkage
case "linkonce":
result |= llvm.LinkOnceAnyLinkage
case "common":
result |= llvm.CommonLinkage
case "weak":
result |= llvm.WeakAnyLinkage
case "appending":
result |= llvm.AppendingLinkage
case "extern_weak":
result |= llvm.ExternalWeakLinkage
case "linkonce_odr":
result |= llvm.LinkOnceODRLinkage
case "weak_odr":
result |= llvm.WeakODRLinkage
case "external":
result |= llvm.ExternalLinkage
case "dllimport":
result |= llvm.DLLImportLinkage
case "dllexport":
result |= llvm.DLLExportLinkage
}
}
return result
}
type nameAttribute string
func (a nameAttribute) Apply(v Value) {
if _, isfunc := v.Type().(*types.Func); isfunc {
fn := v.LLVMValue()
fn.SetName(string(a))
} else {
global := v.(*LLVMValue).pointer.value
global.SetName(string(a))
}
}