-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathslot_verb.go
159 lines (134 loc) · 4.33 KB
/
slot_verb.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
package main
import "fmt"
import "reflect"
import "strings"
import "go/ast"
import "go/types"
// SlotVerbPhrase is an interface that should be implemented by all
// VerbPhrases that concern a slot of the impl struct of the
// VerbPhrase's InterfaceDefinition.
type SlotVerbPhrase interface {
VerbPhrase
SlotName() string
// Type returns the type of the slot. For collection valued
// slots (e.g. for the append/iterate, ... verbs) , this is
// the Slot type of the collection itself (e.g. a slice),
// rather than the element type.
SlotType() types.Type
SlotSpec() *slotSpec
SetSlotSpec(*slotSpec)
TypeString(t types.Type) string
}
type slotVerbPhrase struct {
baseVerbPhrase
slot_name string
slot_spec *slotSpec
slot_type types.Type
}
func (svp *slotVerbPhrase) Description() string {
panic("(*slotVerbPhrase).Description() called.")
}
func (svp *slotVerbPhrase) Tag() string {
panic("(*slotVerbPhrase).Tag() called.")
}
func (svp *slotVerbPhrase) GlobalDefinitions() (string, error) {
panic("(*slotVerbPhrase).GlobalDefinitions() called.")
}
func (svp *slotVerbPhrase) SlotName() string {
return svp.slot_name
}
func (svp *slotVerbPhrase) SlotSpec() *slotSpec {
return svp.slot_spec
}
func (svp *slotVerbPhrase) SetSlotSpec(spec *slotSpec) {
if svp.slot_spec != nil {
panic("slot_spec already set.")
}
svp.slot_spec = spec
}
func (svp *slotVerbPhrase) SlotType() types.Type {
return svp.slot_type
}
func (svp *slotVerbPhrase) TypeString(t types.Type) string {
return types.TypeString(t, svp.InterfaceDefinition().File.Qualifier)
}
type slotSpec struct {
VerbPhrases []SlotVerbPhrase
// emitted is set to true when the slot declaration is added
// to the impl struct. This is so that only one slot is
// defined no matter how namy VerbPhrases concern that slot.
emitted bool
}
func (spec *slotSpec) InterfaceDefinition() *InterfaceDefinition {
return spec.VerbPhrases[0].InterfaceDefinition()
}
func (spec *slotSpec) SlotName() string {
return spec.VerbPhrases[0].(SlotVerbPhrase).SlotName()
}
func (spec *slotSpec) SlotType() types.Type {
return spec.VerbPhrases[0].(SlotVerbPhrase).SlotType()
}
// addSlotSpec searches the InterfaceDefinition for a slotSpec with
// the same slot name as that of svp, and, failiing to find one,
// creates it, updating svf with the slotSpec.
func addSlotSpec(idef *InterfaceDefinition, svp SlotVerbPhrase) error {
// *** IS THIS THE RIGHT TEST FOR TYPE EQUIVALENCE?
teq := func(t1, t2 types.Type) bool {
return (types.AssignableTo(t1, t2) &&
types.AssignableTo(t2, t1))
}
for _, vp := range idef.VerbPhrases {
if svp1, ok := vp.(SlotVerbPhrase); ok {
if svp.SlotName() == svp1.SlotName() {
// Verbs like length might not be able
// to determine, nor need a SlotType.
if svp.SlotType() != nil && !teq(svp.SlotType(), svp1.SlotType()) {
return fmt.Errorf("Types %s and %s don't match",
svp.SlotType(), svp1.SlotType())
}
svp.SetSlotSpec(svp1.SlotSpec())
svp.SlotSpec().VerbPhrases = append(svp.SlotSpec().VerbPhrases, svp)
return nil
}
}
}
svp.SetSlotSpec(&slotSpec {
VerbPhrases: []SlotVerbPhrase { svp },
emitted: false,
})
return nil
}
type slotVerbDefinition struct {}
func (vd *slotVerbDefinition) StructBody(vp VerbPhrase) (string, error) {
svp := vp.(SlotVerbPhrase)
if svp.SlotSpec() == nil {
return "", fmt.Errorf("%#v has no SlotSpec", vp)
}
if !svp.SlotSpec().emitted {
svp.SlotSpec().emitted = true
return fmt.Sprintf("\t%s %s\n", svp.SlotName(),
svp.TypeString(svp.SlotType())), nil
}
return "", nil
}
// parse_slot_verb_phrase parses the defimpl comment for verbs that
// parse to aa SlotVerbPhrase.
func parse_slot_verb_phrase(ctx *context, field *ast.Field, comment *ast.Comment) (string, error) {
val, ok := reflect.StructTag(comment.Text[2:]).Lookup("defimpl")
if !ok {
// Shouldn't happen. To get here we should already have found a defimpl comment.
panic("Can't construct VerbPhrase from a non-defimpl comment.")
}
split := strings.Split(val, " ")
if len(split) != 2 {
pos := ctx.fset.Position(comment.Slash)
return "", fmt.Errorf("defimpl verb %q expects 1 parameter, a slot name: %s %q",
split[0], pos, comment.Text)
}
if len(field.Names) != 1 {
pos := ctx.fset.Position(comment.Slash)
return "", fmt.Errorf("defimpl verb %q requires a field with only one name: %s",
split[0], pos)
}
return split[1], nil
}