-
-
Notifications
You must be signed in to change notification settings - Fork 0
Expand file tree
/
Copy pathexample_test.go
More file actions
224 lines (190 loc) · 5.62 KB
/
Copy pathexample_test.go
File metadata and controls
224 lines (190 loc) · 5.62 KB
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
package luapure_test
import (
"context"
"errors"
"fmt"
"os"
"path/filepath"
"strings"
luapure "github.com/htcom-code/lua-pure/lua"
)
// Build a table in Go, hand it to a script as a global, and read the results
// back — the core embedding round-trip.
func Example_tableExchange() {
L := luapure.NewState()
L.OpenLibs()
cfg := luapure.NewTable()
cfg.SetStr("name", luapure.MkString("luapure"))
cfg.SetStr("level", luapure.Int(5))
L.SetGlobal("config", cfg.Value())
res, err := L.DoString(`return config.name, config.level * 2`, "=embed")
if err != nil {
panic(err)
}
fmt.Println(res[0].Str(), res[1].AsInt())
// Output: luapure 10
}
// Register a Go function that validates its arguments with CheckString, exactly
// like the standard library functions do.
func Example_register() {
L := luapure.NewState()
L.OpenLibs()
L.Register("greet", func(L *luapure.LState) int {
who := L.CheckString(1)
L.Push(luapure.MkString("hello, " + who))
return 1
})
res, _ := L.DoString(`return greet("world")`, "=embed")
fmt.Println(res[0].Str())
// Output: hello, world
}
// A Lua error from a protected Call comes back as a *LuaError carrying the
// raised value.
func ExampleLState_Call() {
L := luapure.NewState()
L.OpenLibs()
res, _ := L.DoString(`return function() error("boom") end`, "=embed")
fn := res[0]
_, err := L.Call(fn, nil, 0)
var le *luapure.LuaError
fmt.Println(errors.As(err, &le), strings.Contains(le.Error(), "boom"))
// Output: true true
}
// ToValue converts Go data into Lua tables; AsTable reads them back.
func ExampleLState_ToValue() {
L := luapure.NewState()
v := L.ToValue([]any{10, 20, 30})
t := v.AsTable()
fmt.Println(t.Len(), t.GetInt(2).AsInt())
// Output: 3 20
}
// FromValue converts a Lua table to a map[any]any.
func ExampleFromValue() {
L := luapure.NewState()
v := L.ToValue(map[string]any{"x": 42})
m := luapure.FromValue(v).(map[any]any)
fmt.Println(m["x"])
// Output: 42
}
// Bind a Go type into Lua as userdata: register a named metatable once, give it
// a method table, then hand scripts a userdata value they call methods on. The
// method recovers the Go value type-checked with CheckUserData.
func Example_userdata() {
type counter struct{ n int64 }
L := luapure.NewState()
L.OpenLibs()
mt, _ := L.NewMetatable("Counter")
methods := luapure.NewTable()
methods.SetStr("inc", luapure.NewGoFunc("inc", func(L *luapure.LState) int {
c := L.CheckUserData(1, "Counter").(*counter)
c.n += L.OptInt(2, 1)
L.Push(luapure.Int(c.n))
return 1
}))
mt.SetStr("__index", methods.Value())
L.SetGlobal("c", L.NewUserData(&counter{}, mt))
res, err := L.DoString(`c:inc(); c:inc(10); return c:inc()`, "=embed")
if err != nil {
panic(err)
}
fmt.Println(res[0].AsInt())
// Output: 12
}
// A uservalue keeps a Lua value associated with (and reachable from) a
// userdatum. Here a script stashes a label on the object and reads it back; the
// host sees the same slot through UserValue.
func Example_uservalue() {
L := luapure.NewState()
L.OpenLibs()
mt, _ := L.NewMetatable("Box")
ud := L.NewUserDataUV(struct{}{}, 1, mt)
L.SetGlobal("box", ud)
if _, err := L.DoString(`debug.setuservalue(box, "hello", 1)`, "=embed"); err != nil {
panic(err)
}
v, _ := ud.UserValue(1)
fmt.Println(v.Str())
// Output: hello
}
// A sandbox state omits the dangerous libraries and the code-loading globals.
func Example_sandbox() {
L := luapure.NewSandbox()
res, _ := L.DoString(`return load == nil, io == nil, (1 + 2)`, "=embed")
fmt.Println(res[0].AsBool(), res[1].AsBool(), res[2].AsInt())
// Output: true true 3
}
// RunWith confines a chunk to a custom _ENV: it sees only the globals you put
// in env.
func ExampleLState_RunWith() {
L := luapure.NewState()
env := luapure.NewTable()
env.SetStr("x", luapure.Int(21))
res, err := L.RunWith(env, `return x * 2`, "=embed")
if err != nil {
panic(err)
}
fmt.Println(res[0].AsInt())
// Output: 42
}
// A cancelled context interrupts even a tight infinite loop.
func ExampleLState_SetContext() {
L := luapure.NewState()
L.OpenLibs()
ctx, cancel := context.WithCancel(context.Background())
cancel() // already cancelled before we run
L.SetContext(ctx)
_, err := L.DoString(`while true do end`, "=embed")
fmt.Println(err != nil)
// Output: true
}
// CompileReader compiles source streamed from any io.Reader.
func ExampleCompileReader() {
L := luapure.NewState()
L.OpenLibs()
p, err := luapure.CompileReader(strings.NewReader(`return 6 * 7`), "=embed")
if err != nil {
panic(err)
}
res, _ := L.CallProto(p, 1)
fmt.Println(res[0].AsInt())
// Output: 42
}
// DoFile loads and runs a script from disk.
func ExampleLState_DoFile() {
L := luapure.NewState()
L.OpenLibs()
dir, _ := os.MkdirTemp("", "luapure")
defer os.RemoveAll(dir)
path := filepath.Join(dir, "s.lua")
if err := os.WriteFile(path, []byte(`return 1 + 2 + 3`), 0o644); err != nil {
panic(err)
}
res, err := L.DoFile(path)
if err != nil {
panic(err)
}
fmt.Println(res[0].AsInt())
// Output: 6
}
// Close releases the state's resources and is idempotent.
func ExampleLState_Close() {
L := luapure.NewState()
L.OpenLibs()
L.Close()
L.Close()
fmt.Println("ok")
// Output: ok
}
// NewState options fold setup into one call: open the standard libraries and
// cap a limit for this state only. WithMaxStack/WithMaxCCalls/
// WithMaxTableArraySize override the package globals for this state, leaving
// other states on the process-wide defaults.
func ExampleNewState_options() {
L := luapure.NewState(luapure.WithOpenLibs(), luapure.WithMaxStack(50000))
res, err := L.DoString(`return math.max(2, 7)`, "=opts")
if err != nil {
panic(err)
}
fmt.Println(res[0].AsInt())
// Output: 7
}