-
Notifications
You must be signed in to change notification settings - Fork 1
/
gong_marshall.go
290 lines (228 loc) · 9.8 KB
/
gong_marshall.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
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
// generated code - do not edit
package models
import (
"fmt"
"log"
"os"
"path/filepath"
"regexp"
"sort"
"strings"
)
const marshallRes = `package {{PackageName}}
import (
"time"
"{{ModelsPackageName}}"
// injection point for ident package import declaration{{ImportPackageDeclaration}}
)
// generated in order to avoid error in the package import
// if there are no elements in the stage to marshall
var ___dummy__Stage_{{databaseName}} models.StageStruct
var ___dummy__Time_{{databaseName}} time.Time
// Injection point for meta package dummy declaration{{ImportPackageDummyDeclaration}}
// currently, DocLink renaming is not enabled in gopls
// the following map are devised to overcome this limitation
// those maps and the processing code will be eleminated when
// DocLink renaming will be enabled in gopls
// [Corresponding Issue](https://github.com/golang/go/issues/57559)
//
// When parsed, those maps will help with the renaming process
var map_DocLink_Identifier_{{databaseName}} map[string]any = map[string]any{
// injection point for docLink to identifiers{{EntriesDocLinkStringDocLinkIdentifier}}
}
// init might be handy if one want to have the data embedded in the binary
// but it has to properly reference the Injection gateway in the main package
// func init() {
// _ = __Dummy_time_variable
// InjectionGateway["{{databaseName}}"] = {{databaseName}}Injection
// }
// {{databaseName}}Injection will stage objects of database "{{databaseName}}"
func {{databaseName}}Injection(stage *models.StageStruct) {
// Declaration of instances to stage{{Identifiers}}
// Setup of values{{ValueInitializers}}
// Setup of pointers{{PointersInitializers}}
}
`
const IdentifiersDecls = `
{{Identifier}} := (&models.{{GeneratedStructName}}{Name: ` + "`" + `{{GeneratedFieldNameValue}}` + "`" + `}).Stage(stage)`
const StringInitStatement = `
{{Identifier}}.{{GeneratedFieldName}} = ` + "`" + `{{GeneratedFieldNameValue}}` + "`"
const StringEnumInitStatement = `
{{Identifier}}.{{GeneratedFieldName}} = {{GeneratedFieldNameValue}}`
const NumberInitStatement = `
{{Identifier}}.{{GeneratedFieldName}} = {{GeneratedFieldNameValue}}`
const PointerFieldInitStatement = `
{{Identifier}}.{{GeneratedFieldName}} = {{GeneratedFieldNameValue}}`
const SliceOfPointersFieldInitStatement = `
{{Identifier}}.{{GeneratedFieldName}} = append({{Identifier}}.{{GeneratedFieldName}}, {{GeneratedFieldNameValue}})`
const TimeInitStatement = `
{{Identifier}}.{{GeneratedFieldName}}, _ = time.Parse("2006-01-02 15:04:05.999999999 -0700 MST", "{{GeneratedFieldNameValue}}")`
// Marshall marshall the stage content into the file as an instanciation into a stage
func (stage *StageStruct) Marshall(file *os.File, modelsPackageName, packageName string) {
name := file.Name()
if !strings.HasSuffix(name, ".go") {
log.Fatalln(name + " is not a go filename")
}
log.Println("filename of marshall output is " + name)
newBase := filepath.Base(file.Name())
res := marshallRes
res = strings.ReplaceAll(res, "{{databaseName}}", strings.ReplaceAll(newBase, ".go", ""))
res = strings.ReplaceAll(res, "{{PackageName}}", packageName)
res = strings.ReplaceAll(res, "{{ModelsPackageName}}", modelsPackageName)
// map of identifiers
// var StageMapDstructIds map[*Dstruct]string
identifiersDecl := ""
initializerStatements := ""
pointersInitializesStatements := ""
id := ""
_ = id
decl := ""
_ = decl
setValueField := ""
_ = setValueField
// insertion initialization of objects to stage
map_A_Identifiers := make(map[*A]string)
_ = map_A_Identifiers
aOrdered := []*A{}
for a := range stage.As {
aOrdered = append(aOrdered, a)
}
sort.Slice(aOrdered[:], func(i, j int) bool {
return aOrdered[i].Name < aOrdered[j].Name
})
identifiersDecl += "\n\n // Declarations of staged instances of A"
for idx, a := range aOrdered {
id = generatesIdentifier("A", idx, a.Name)
map_A_Identifiers[a] = id
decl = IdentifiersDecls
decl = strings.ReplaceAll(decl, "{{Identifier}}", id)
decl = strings.ReplaceAll(decl, "{{GeneratedStructName}}", "A")
decl = strings.ReplaceAll(decl, "{{GeneratedFieldNameValue}}", a.Name)
identifiersDecl += decl
initializerStatements += "\n\n // A values setup"
// Initialisation of values
setValueField = StringInitStatement
setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "Name")
setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", string(a.Name))
initializerStatements += setValueField
setValueField = NumberInitStatement
setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "NumberField")
setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", fmt.Sprintf("%d", a.NumberField))
initializerStatements += setValueField
}
map_B_Identifiers := make(map[*B]string)
_ = map_B_Identifiers
bOrdered := []*B{}
for b := range stage.Bs {
bOrdered = append(bOrdered, b)
}
sort.Slice(bOrdered[:], func(i, j int) bool {
return bOrdered[i].Name < bOrdered[j].Name
})
identifiersDecl += "\n\n // Declarations of staged instances of B"
for idx, b := range bOrdered {
id = generatesIdentifier("B", idx, b.Name)
map_B_Identifiers[b] = id
decl = IdentifiersDecls
decl = strings.ReplaceAll(decl, "{{Identifier}}", id)
decl = strings.ReplaceAll(decl, "{{GeneratedStructName}}", "B")
decl = strings.ReplaceAll(decl, "{{GeneratedFieldNameValue}}", b.Name)
identifiersDecl += decl
initializerStatements += "\n\n // B values setup"
// Initialisation of values
setValueField = StringInitStatement
setValueField = strings.ReplaceAll(setValueField, "{{Identifier}}", id)
setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldName}}", "Name")
setValueField = strings.ReplaceAll(setValueField, "{{GeneratedFieldNameValue}}", string(b.Name))
initializerStatements += setValueField
}
// insertion initialization of objects to stage
for idx, a := range aOrdered {
var setPointerField string
_ = setPointerField
id = generatesIdentifier("A", idx, a.Name)
map_A_Identifiers[a] = id
// Initialisation of values
if a.B != nil {
setPointerField = PointerFieldInitStatement
setPointerField = strings.ReplaceAll(setPointerField, "{{Identifier}}", id)
setPointerField = strings.ReplaceAll(setPointerField, "{{GeneratedFieldName}}", "B")
setPointerField = strings.ReplaceAll(setPointerField, "{{GeneratedFieldNameValue}}", map_B_Identifiers[a.B])
pointersInitializesStatements += setPointerField
}
for _, _b := range a.Bs {
setPointerField = SliceOfPointersFieldInitStatement
setPointerField = strings.ReplaceAll(setPointerField, "{{Identifier}}", id)
setPointerField = strings.ReplaceAll(setPointerField, "{{GeneratedFieldName}}", "Bs")
setPointerField = strings.ReplaceAll(setPointerField, "{{GeneratedFieldNameValue}}", map_B_Identifiers[_b])
pointersInitializesStatements += setPointerField
}
}
for idx, b := range bOrdered {
var setPointerField string
_ = setPointerField
id = generatesIdentifier("B", idx, b.Name)
map_B_Identifiers[b] = id
// Initialisation of values
}
res = strings.ReplaceAll(res, "{{Identifiers}}", identifiersDecl)
res = strings.ReplaceAll(res, "{{ValueInitializers}}", initializerStatements)
res = strings.ReplaceAll(res, "{{PointersInitializers}}", pointersInitializesStatements)
if stage.MetaPackageImportAlias != "" {
res = strings.ReplaceAll(res, "{{ImportPackageDeclaration}}",
fmt.Sprintf("\n\t%s %s", stage.MetaPackageImportAlias, stage.MetaPackageImportPath))
res = strings.ReplaceAll(res, "{{ImportPackageDummyDeclaration}}",
fmt.Sprintf("\nvar ___dummy__%s_%s %s.StageStruct",
stage.MetaPackageImportAlias,
strings.ReplaceAll(filepath.Base(name), ".go", ""),
stage.MetaPackageImportAlias))
var entries string
// regenerate the map of doc link renaming
// the key and value are set to the value because
// if it has been renamed, this is the new value that matters
valuesOrdered := make([]GONG__Identifier, 0)
for _, value := range stage.Map_DocLink_Renaming {
valuesOrdered = append(valuesOrdered, value)
}
sort.Slice(valuesOrdered[:], func(i, j int) bool {
return valuesOrdered[i].Ident < valuesOrdered[j].Ident
})
for _, value := range valuesOrdered {
// get the number of points in the value to find if it is a field
// or a struct
switch value.Type {
case GONG__ENUM_CAST_INT:
entries += fmt.Sprintf("\n\n\t\"%s\": %s(0),", value.Ident, value.Ident)
case GONG__ENUM_CAST_STRING:
entries += fmt.Sprintf("\n\n\t\"%s\": %s(\"\"),", value.Ident, value.Ident)
case GONG__FIELD_VALUE:
// substitute the second point with "{})."
joker := "__substitute_for_first_point__"
valueIdentifier := strings.Replace(value.Ident, ".", joker, 1)
valueIdentifier = strings.Replace(valueIdentifier, ".", "{}).", 1)
valueIdentifier = strings.Replace(valueIdentifier, joker, ".", 1)
entries += fmt.Sprintf("\n\n\t\"%s\": (%s,", value.Ident, valueIdentifier)
case GONG__IDENTIFIER_CONST:
entries += fmt.Sprintf("\n\n\t\"%s\": %s,", value.Ident, value.Ident)
case GONG__STRUCT_INSTANCE:
entries += fmt.Sprintf("\n\n\t\"%s\": &(%s{}),", value.Ident, value.Ident)
}
}
res = strings.ReplaceAll(res, "{{EntriesDocLinkStringDocLinkIdentifier}}", entries)
}
fmt.Fprintln(file, res)
}
// unique identifier per struct
func generatesIdentifier(gongStructName string, idx int, instanceName string) (identifier string) {
identifier = instanceName
// Make a Regex to say we only want letters and numbers
reg, err := regexp.Compile("[^a-zA-Z0-9]+")
if err != nil {
log.Fatal(err)
}
processedString := reg.ReplaceAllString(instanceName, "_")
identifier = fmt.Sprintf("__%s__%06d_%s", gongStructName, idx, processedString)
return
}