-
Notifications
You must be signed in to change notification settings - Fork 0
/
Copy pathmodule.go
234 lines (222 loc) · 5.75 KB
/
module.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
// Package glu support yuin/gopher-lua with easy modular definition and other enchantments.
// glu.Modular and gua.BaseType will inject mod.Help(name string?) method to output HelpCache information.
// glu.Get: Pool function to get a lua.LState.
// glu.Put: Pool function to return a lua.LState.
// glu.modulars: shared module modulars.
// glu.Auto: config for autoload modules in modulars into lua.LState.
package glu
import (
"fmt"
. "github.com/yuin/gopher-lua"
"strings"
)
type (
Module interface {
Modular
// AddFunc add function to this Module
//
// @name function name, must match lua limitation
//
// @help help string, if empty will generate just Module.Function as help
//
// @fn the LGFunction
AddFunc(name string, help string, fn LGFunction) Module
// AddField add value field to this Module (static value)
AddField(name string, help string, value LValue) Module
// AddFieldSupplier add value field to this Module (static value from a Supplier)
AddFieldSupplier(name string, help string, su func(s *LState) LValue) Module
// AddModule add submodule to this Module
//
// @mod the Mod , requires Mod.TopLevel is false.
AddModule(mod Modular) Module
}
fieldInfo struct {
Help string
Value LValue
Supplier func(s *LState) LValue
}
funcInfo struct {
Help string
Func LGFunction
}
//Mod define a Mod only contains Functions and value fields,maybe with Submodules
Mod struct {
Name string //Name of Modular
Top bool //is top level
Help string //Help information of this Modular
functions map[string]funcInfo //registered functions
fields map[string]fieldInfo //registered fields
Submodules []Modular //registered sub modules
prepared bool //compute helper and other things, should just do once
HelpCache map[string]string //exported helps for better use
}
)
// NewModule create New Mod
func NewModule(name string, help string, top bool) *Mod {
return &Mod{Name: name, Help: help, Top: top}
}
func (m *Mod) TopLevel() bool {
return m.Top
}
func (m *Mod) GetName() string {
return m.Name
}
func (m *Mod) GetHelp() string {
return m.Help
}
func (m *Mod) prepare() {
if m.prepared {
return
}
help := make(map[string]string)
mh := new(strings.Builder) //mod HelpCache builder
if m.Help != "" {
mh.WriteString(m.Help)
mh.WriteRune('\n')
} else {
mh.WriteString(m.Name)
mh.WriteRune('\n')
}
helpFuncReg(m.functions, help, mh, m.Name)
helpFieldReg(m.fields, help, mh, m.Name)
helpSubModReg(m.Submodules, help, mh, m.Name)
if mh.Len() > 0 {
help[HelpKey] = mh.String()
}
if EagerHelpPrepare && len(m.Submodules) > 0 {
for _, sub := range m.Submodules {
switch sub.(type) {
case Prepare:
sub.(Prepare).prepare()
}
}
}
m.HelpCache = help
m.prepared = true
}
func (m *Mod) PreLoad(l *LState) {
if !m.Top {
return
}
m.prepare()
l.PreloadModule(m.Name, func(l *LState) int {
mod := l.NewTable()
fn := make(map[string]LGFunction)
if len(m.functions) > 0 {
for s, info := range m.functions {
fn[s] = info.Func
}
}
if len(m.fields) > 0 {
for key, value := range m.fields {
if value.Supplier != nil {
l.SetField(mod, key, value.Supplier(l))
} else if value.Value != LNil {
l.SetField(mod, key, value.Value)
} else {
panic(fmt.Errorf(`invalid field info`))
}
}
}
if len(m.Submodules) > 0 {
for _, t := range m.Submodules {
t.PreloadSubModule(l, mod)
}
}
if len(m.HelpCache) > 0 {
fn[HelpFunc] = helpFn(m.HelpCache)
}
if len(fn) > 0 {
l.SetFuncs(mod, fn)
}
l.Push(mod)
return 1
})
}
func (m *Mod) PreloadSubModule(l *LState, t *LTable) {
if m.Top {
return
}
m.prepare()
mod := l.NewTable()
fn := make(map[string]LGFunction)
if len(m.functions) > 0 {
for s, info := range m.functions {
fn[s] = info.Func
}
}
if len(m.fields) > 0 {
for key, value := range m.fields {
if value.Supplier != nil {
l.SetField(mod, key, value.Supplier(l))
} else if value.Value != LNil {
l.SetField(mod, key, value.Value)
} else {
panic(fmt.Errorf(`invalid field info`))
}
}
}
if len(m.Submodules) > 0 {
for _, s := range m.Submodules {
s.PreloadSubModule(l, mod)
}
}
if len(m.HelpCache) > 0 {
fn[HelpFunc] = helpFn(m.HelpCache)
}
if len(fn) > 0 {
l.SetFuncs(mod, fn)
}
l.SetField(t, m.Name, mod)
}
// AddFunc add function to this Modular
//
// @name function name, must match lua limitation
//
// @HelpCache HelpCache string, if empty will not generate into HelpCache
//
// @fn the LGFunction
func (m *Mod) AddFunc(name string, help string, fn LGFunction) Module {
if m.functions == nil {
m.functions = make(map[string]funcInfo)
} else if _, ok := m.functions[name]; ok {
panic(ErrAlreadyExists)
}
m.functions[name] = funcInfo{help, fn}
return m
}
// AddField add value field to this Modular
//
// @name the field name
//
// @HelpCache HelpCache string, if empty will not generate into HelpCache
//
// @value the field value
func (m *Mod) AddField(name string, help string, value LValue) Module {
if m.fields == nil {
m.fields = make(map[string]fieldInfo)
} else if _, ok := m.fields[name]; ok {
panic(ErrAlreadyExists)
}
m.fields[name] = fieldInfo{help, value, nil}
return m
}
func (m *Mod) AddFieldSupplier(name string, help string, su func(s *LState) LValue) Module {
if m.fields == nil {
m.fields = make(map[string]fieldInfo)
} else if _, ok := m.fields[name]; ok {
panic(ErrAlreadyExists)
}
m.fields[name] = fieldInfo{help, LNil, su}
return m
}
// AddModule add sub-module to this Modular
//
// @mod the Mod **Note** must with TopLevel false.
func (m *Mod) AddModule(mod Modular) Module {
if mod.TopLevel() {
panic(ErrIsTop)
}
m.Submodules = append(m.Submodules, mod)
return m
}