-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathattribute.go
More file actions
135 lines (119 loc) · 3.88 KB
/
Copy pathattribute.go
File metadata and controls
135 lines (119 loc) · 3.88 KB
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
128
129
130
131
132
133
134
135
package analysis
import (
"fmt"
"github.com/ProCode-Software/klar/internal/ast"
"github.com/ProCode-Software/klar/internal/klarerrs"
"github.com/ProCode-Software/klar/internal/ranges"
"github.com/ProCode-Software/klar/internal/target"
"github.com/ProCode-Software/klar/internal/version"
)
// Contains the definitions of attributes
var attributesModule *Module
// All fields are optional
type Attributes struct {
Deprecated *Deprecation
External []*External
Target []target.Target
Added version.Version
Name map[target.Target]string
}
// All fields are optional
type Deprecation struct {
Reason string
Since version.Version
Use string // What users should use instead
// Specific targets this is deprecated on. If not specified,
// the deprecation applies to all targets.
On []target.Target
}
type External struct{}
type attrMode uint8
const (
// @added and @deprecated are allowed on all declarations
nameAttr attrMode = 1 << iota
targetAttr
externalAttr
enumVariantAttrs = nameAttr
funcAliasAttrs = nameAttr
funcAttrs = nameAttr | targetAttr | externalAttr
intfAttrs = 0 // @deprecated and @added only
intfFieldAttrs = nameAttr | targetAttr
structFieldAttrs = nameAttr
typeAttrs = nameAttr
tagAttrs = 0
typeAliasAttrs = externalAttr
varAttrs = nameAttr | externalAttr
)
func (c *Checker) parseAttributes(attrs []*ast.Attribute,
target attrTarget, nodeRange ranges.Range, fid FileID,
) *Attributes {
if len(attrs) == 0 {
return nil
}
a := &Attributes{}
for _, stmt := range attrs {
c.parseAttribute(a, stmt, target, nodeRange, fid)
}
return a
}
// parseAttribute parses a single attribute into the corresponding field in a.
func (c *Checker) parseAttribute(a *Attributes, attr *ast.Attribute,
t attrTarget, nodeRange ranges.Range, fid FileID,
) {
// TODO: Should this be a limitation?
if attributesModule == c.module {
panic("klar._builtin.attributes module can't reference attributes")
}
name := attr.Name.Name
def := attributesModule.Context.Lookup(name)
if def == nil || !def.Public || def.Kind() != KindFunction {
// Unknown attribute
err := klarerrs.Node(klarerrs.ErrUnknownAttribute, attr.Name)
err.Name = name
err.Label = "Unknown attribute " + klarerrs.Quote(name)
c.fileError(err, fid)
return
}
// Check if the attribute is supported on the current declaration type
if mode := map[string]attrMode{
"name": nameAttr, "target": targetAttr, "external": externalAttr,
// Attributes not in this map are supported on all declarations
}[name]; mode != 0 && !t.supports(mode) {
}
}
type attrTarget struct {
node ast.Node
str string
mode attrMode
public bool
}
func (t attrTarget) supports(m attrMode) bool { return (t.mode & m) != 0 }
func attrTargetKindOf(n ast.Node, public bool) attrTarget {
switch n.(type) {
// Other declarations
case *ast.FunctionDeclaration:
return attrTarget{n, "a function", funcAttrs, public}
case *ast.VariableDeclaration:
return attrTarget{n, "a variable", varAttrs, public}
case *ast.FuncAliasDeclaration:
return attrTarget{n, "a function alias", funcAliasAttrs, public}
// Type declarations
case *ast.TypeAliasDeclaration:
return attrTarget{n, "a type alias", typeAliasAttrs, public}
case *ast.InterfaceDeclaration:
return attrTarget{n, "an interface", intfAttrs, public}
case *ast.StructDeclaration, *ast.EnumDeclaration:
return attrTarget{n, "a type", typeAttrs, public}
case *ast.TagDeclaration:
return attrTarget{n, "a tag", tagAttrs, public}
// Entries in type declarations
case *ast.EnumItem:
return attrTarget{n, "an enum variant", enumVariantAttrs, public}
case *ast.InterfaceItem:
return attrTarget{n, "an interface field", intfFieldAttrs, public}
case *ast.StructField:
return attrTarget{n, "a struct field", structFieldAttrs, public}
}
panic(fmt.Sprintf("unhandled or unsupported attribute target: %T", n))
// return unsupportedAttr
}