/
type.go
189 lines (164 loc) · 5.73 KB
/
type.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
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
// Copyright (c) 2017 Uber Technologies, Inc.
//
// Permission is hereby granted, free of charge, to any person obtaining a copy
// of this software and associated documentation files (the "Software"), to deal
// in the Software without restriction, including without limitation the rights
// to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
// copies of the Software, and to permit persons to whom the Software is
// furnished to do so, subject to the following conditions:
//
// The above copyright notice and this permission notice shall be included in
// all copies or substantial portions of the Software.
//
// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
// IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
// FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
// AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
// LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
// OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
// THE SOFTWARE.
package compile
import (
"fmt"
"go.uber.org/thriftrw/ast"
"go.uber.org/thriftrw/wire"
)
// NamedEntity is any Thrift entity with a name and annotations. Not all
// entities are TypeSpecs.
type NamedEntity interface {
// ThriftName is the name of the type as it appears in the Thrift file.
ThriftName() string
// ThriftAnnotations is the map of all associated annotations from the Thrift file.
ThriftAnnotations() Annotations
}
// TypeSpec contains information about Thrift types.
type TypeSpec interface {
NamedEntity
// Link resolves references to other types in this TypeSpecs to actual
// TypeSpecs from the given Scope.
Link(scope Scope) (TypeSpec, error)
// TypeCode is the wire-level Thrift Type associated with this Type.
TypeCode() wire.Type
// ThriftFile is the path to the Thrift file in which this TypeSpec was
// defined. This may be an empty string if this type is a native Thrift
// type.
ThriftFile() string
// Applies the given function to each TypeSpec referenced by this
// TypeSpec. This function MUST NOT be automatically called recursively on
// the TypeSpecs referenced by the child TypeSpecs. The decision to make
// that call is up to the caller of this function.
//
// Returns the first error returned by the function call or nil.
ForEachTypeReference(func(TypeSpec) error) error
}
// RootTypeSpec returns the TypeSpec that the given linked TypeSpec points to.
//
// For most types, this is the type itself. For Typedefs, it is the root
// TypeSpec of the Typedef's target.
func RootTypeSpec(s TypeSpec) TypeSpec {
if t, ok := s.(*TypedefSpec); ok {
return t.root
}
return s
}
// nativeThriftType is the common parent for all TypeSpecs that are native
// Thrift types.
type nativeThriftType struct{}
func (nativeThriftType) ThriftFile() string { return "" }
// typeSpecReference is a dummy TypeSpec that represents a reference to another
// TypeSpec. These will be replaced with actual TypeSpecs during the Link()
// step.
type typeSpecReference ast.TypeReference
// Link replaces the typeSpecReference with an actual linked TypeSpec.
func (r typeSpecReference) Link(scope Scope) (TypeSpec, error) {
src := ast.TypeReference(r)
t, err := scope.LookupType(src.Name)
if err == nil {
return t.Link(scope)
}
mname, iname := splitInclude(src.Name)
if len(mname) == 0 {
return nil, referenceError{
Target: src.Name,
Line: src.Line,
ScopeName: scope.GetName(),
Reason: err,
}
}
includedScope, err := getIncludedScope(scope, mname)
if err != nil {
return nil, referenceError{
Target: src.Name,
Line: src.Line,
ScopeName: scope.GetName(),
Reason: err,
}
}
t, err = typeSpecReference{Name: iname}.Link(includedScope)
if err != nil {
return nil, referenceError{
Target: src.Name,
Line: src.Line,
ScopeName: scope.GetName(),
Reason: err,
}
}
return t, nil
}
// TypeCode on an unresolved typeSpecReference will cause a system panic.
func (r typeSpecReference) TypeCode() wire.Type {
panic(fmt.Sprintf(
"TypeCode() requested for unresolved TypeSpec reference %v."+
"Make sure you called Link().", r,
))
}
// ThriftFile on an unresolved typeSpecReference will cause a system panic.
func (r typeSpecReference) ThriftFile() string {
panic(fmt.Sprintf(
"ThriftFile() requested for unresolved TypeSpec reference %v."+
"Make sure you called Link().", r,
))
}
// ForEachTypeReference on an unresolved typeSpecReference will cause a system
// panic.
func (r typeSpecReference) ForEachTypeReference(func(TypeSpec) error) error {
panic(fmt.Sprintf(
"ForEachTypeReference() called on unresolved TypeSpec reference %v."+
"Make sure you called Link().", r,
))
}
// ThriftName is the name of the typeSpecReference as it appears in the Thrift
// file.
func (r typeSpecReference) ThriftName() string {
return r.Name
}
// ForEachTypeReference on an unresolved typeSpecReference will cause a system
// panic.
func (r typeSpecReference) ThriftAnnotations() Annotations {
panic(fmt.Sprintf(
"ThriftAnnotations() called on unresolved TypeSpec reference %v."+
"Make sure you called Link().", r,
))
}
// compileTypeReference compiles the given AST type reference into a TypeSpec.
//
// The returned TypeSpec may need to be linked eventually.
func compileTypeReference(typ ast.Type) (TypeSpec, error) {
if typ == nil {
return nil, nil
}
switch t := typ.(type) {
case ast.BaseType:
return compileBaseType(t)
case ast.MapType:
return compileMapType(t)
case ast.ListType:
return compileListType(t)
case ast.SetType:
return compileSetType(t)
case ast.TypeReference:
return typeSpecReference(t), nil
default:
panic(fmt.Sprintf("unknown type %v", typ))
}
}