/
generator.go
134 lines (118 loc) · 3.56 KB
/
generator.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
package main
import (
"fmt"
"strings"
"unicode"
)
func writeGoCode(flags Flags, parsedFile ParsedFile, builder *strings.Builder) {
builder.WriteString("// Generated code by github.com/choonkeat/sumtype-go\npackage ")
builder.WriteString(parsedFile.PackageName)
builder.WriteString("\n\n")
if len(parsedFile.Imports) > 0 {
builder.WriteString("import (\n")
for _, imp := range parsedFile.Imports {
builder.WriteString("\t\"")
builder.WriteString(imp)
builder.WriteString("\"\n")
}
builder.WriteString(")\n")
}
for _, data := range parsedFile.Data {
structName := unexported(data.Name) + parsedFile.Name
genericsDecl := buildGenericTypeDeclaration(data.Generics)
paramList := buildParameterListDeclaration(data.Generics)
// Generate struct
fmt.Fprintf(builder, "\n// %s\n", data.Name)
fmt.Fprintf(builder, "type %s%s struct {\n", structName, genericsDecl)
for _, field := range data.Fields {
fmt.Fprintf(builder, "\t%s %s\n", field.Name, field.Type)
}
fmt.Fprintf(builder, "}\n\n")
// Generate method
fmt.Fprintf(builder, "func (s %s%s) %s(scenarios %s%s) {\n", structName, paramList, flags.switchName, parsedFile.Name, paramList)
if len(data.Fields) > 0 {
fmt.Fprintf(builder,
"\tscenarios.%s(s.%s)\n",
data.Name,
strings.Join(getFieldNames("", data.Fields), ", s."),
)
} else {
fmt.Fprintf(builder, "\tscenarios.%s()\n", data.Name)
}
fmt.Fprintf(builder, "}\n\n")
// Generate constructor function
fmt.Fprintf(builder,
"func %s%s(%s) %s%s {\n",
data.Name,
genericsDecl,
getParamList("Arg", data.Fields),
strings.TrimSuffix(parsedFile.Name, flags.structSuffix),
paramList,
)
if len(data.Fields) > 0 {
fmt.Fprintf(builder,
"\treturn %s%s{%s}\n",
structName,
paramList,
strings.Join(getFieldNames("Arg", data.Fields), ", "),
)
} else {
fmt.Fprintf(builder, "\treturn %s%s{}\n", structName, paramList)
}
fmt.Fprintf(builder, "}\n")
}
}
// unexported returns an unexported (lowercase) version of the given string
func unexported(s string) string {
if s == "" {
return ""
}
r := []rune(s)
r[0] = unicode.ToLower(r[0])
return string(r)
}
// getFieldNames returns a slice of field names from a slice of ParsedField
func getFieldNames(suffix string, fields []ParsedField) []string {
var names []string
for _, field := range fields {
names = append(names, field.Name+suffix)
}
return names
}
// getParamList returns a string representing the parameter list for a function
func getParamList(suffix string, fields []ParsedField) string {
var params []string
for _, field := range fields {
params = append(params, fmt.Sprintf("%s%s %s", field.Name, suffix, field.Type))
}
return strings.Join(params, ", ")
}
func buildGenericTypeDeclaration(data []ParsedGeneric) string {
if len(data) == 0 {
return ""
}
constraintMap := make(map[string][]string)
var constraintsOrder []string
for _, d := range data {
if _, exists := constraintMap[d.Constraint]; !exists {
constraintsOrder = append(constraintsOrder, d.Constraint)
}
constraintMap[d.Constraint] = append(constraintMap[d.Constraint], d.Name)
}
var result []string
for _, constraint := range constraintsOrder {
names := constraintMap[constraint]
result = append(result, fmt.Sprintf("%s %s", strings.Join(names, ", "), constraint))
}
return "[" + strings.Join(result, ", ") + "]"
}
func buildParameterListDeclaration(data []ParsedGeneric) string {
if len(data) == 0 {
return ""
}
var names []string
for _, d := range data {
names = append(names, d.Name)
}
return "[" + strings.Join(names, ", ") + "]"
}