1package lua
2
3import (
4	"bufio"
5	"fmt"
6	"io"
7	"os"
8	"strings"
9)
10
11/* checkType {{{ */
12
13func (ls *LState) CheckAny(n int) LValue {
14	if n > ls.GetTop() {
15		ls.ArgError(n, "value expected")
16	}
17	return ls.Get(n)
18}
19
20func (ls *LState) CheckInt(n int) int {
21	v := ls.Get(n)
22	if intv, ok := v.(LNumber); ok {
23		return int(intv)
24	}
25	ls.TypeError(n, LTNumber)
26	return 0
27}
28
29func (ls *LState) CheckInt64(n int) int64 {
30	v := ls.Get(n)
31	if intv, ok := v.(LNumber); ok {
32		return int64(intv)
33	}
34	ls.TypeError(n, LTNumber)
35	return 0
36}
37
38func (ls *LState) CheckNumber(n int) LNumber {
39	v := ls.Get(n)
40	if lv, ok := v.(LNumber); ok {
41		return lv
42	}
43	ls.TypeError(n, LTNumber)
44	return 0
45}
46
47func (ls *LState) CheckString(n int) string {
48	v := ls.Get(n)
49	if lv, ok := v.(LString); ok {
50		return string(lv)
51	} else if LVCanConvToString(v) {
52		return ls.ToString(n)
53	}
54	ls.TypeError(n, LTString)
55	return ""
56}
57
58func (ls *LState) CheckBool(n int) bool {
59	v := ls.Get(n)
60	if lv, ok := v.(LBool); ok {
61		return bool(lv)
62	}
63	ls.TypeError(n, LTBool)
64	return false
65}
66
67func (ls *LState) CheckTable(n int) *LTable {
68	v := ls.Get(n)
69	if lv, ok := v.(*LTable); ok {
70		return lv
71	}
72	ls.TypeError(n, LTTable)
73	return nil
74}
75
76func (ls *LState) CheckFunction(n int) *LFunction {
77	v := ls.Get(n)
78	if lv, ok := v.(*LFunction); ok {
79		return lv
80	}
81	ls.TypeError(n, LTFunction)
82	return nil
83}
84
85func (ls *LState) CheckUserData(n int) *LUserData {
86	v := ls.Get(n)
87	if lv, ok := v.(*LUserData); ok {
88		return lv
89	}
90	ls.TypeError(n, LTUserData)
91	return nil
92}
93
94func (ls *LState) CheckThread(n int) *LState {
95	v := ls.Get(n)
96	if lv, ok := v.(*LState); ok {
97		return lv
98	}
99	ls.TypeError(n, LTThread)
100	return nil
101}
102
103func (ls *LState) CheckType(n int, typ LValueType) {
104	v := ls.Get(n)
105	if v.Type() != typ {
106		ls.TypeError(n, typ)
107	}
108}
109
110func (ls *LState) CheckTypes(n int, typs ...LValueType) {
111	vt := ls.Get(n).Type()
112	for _, typ := range typs {
113		if vt == typ {
114			return
115		}
116	}
117	buf := []string{}
118	for _, typ := range typs {
119		buf = append(buf, typ.String())
120	}
121	ls.ArgError(n, strings.Join(buf, " or ")+" expected, got "+ls.Get(n).Type().String())
122}
123
124func (ls *LState) CheckOption(n int, options []string) int {
125	str := ls.CheckString(n)
126	for i, v := range options {
127		if v == str {
128			return i
129		}
130	}
131	ls.ArgError(n, fmt.Sprintf("invalid option: %s (must be one of %s)", str, strings.Join(options, ",")))
132	return 0
133}
134
135/* }}} */
136
137/* optType {{{ */
138
139func (ls *LState) OptInt(n int, d int) int {
140	v := ls.Get(n)
141	if v == LNil {
142		return d
143	}
144	if intv, ok := v.(LNumber); ok {
145		return int(intv)
146	}
147	ls.TypeError(n, LTNumber)
148	return 0
149}
150
151func (ls *LState) OptInt64(n int, d int64) int64 {
152	v := ls.Get(n)
153	if v == LNil {
154		return d
155	}
156	if intv, ok := v.(LNumber); ok {
157		return int64(intv)
158	}
159	ls.TypeError(n, LTNumber)
160	return 0
161}
162
163func (ls *LState) OptNumber(n int, d LNumber) LNumber {
164	v := ls.Get(n)
165	if v == LNil {
166		return d
167	}
168	if lv, ok := v.(LNumber); ok {
169		return lv
170	}
171	ls.TypeError(n, LTNumber)
172	return 0
173}
174
175func (ls *LState) OptString(n int, d string) string {
176	v := ls.Get(n)
177	if v == LNil {
178		return d
179	}
180	if lv, ok := v.(LString); ok {
181		return string(lv)
182	}
183	ls.TypeError(n, LTString)
184	return ""
185}
186
187func (ls *LState) OptBool(n int, d bool) bool {
188	v := ls.Get(n)
189	if v == LNil {
190		return d
191	}
192	if lv, ok := v.(LBool); ok {
193		return bool(lv)
194	}
195	ls.TypeError(n, LTBool)
196	return false
197}
198
199func (ls *LState) OptTable(n int, d *LTable) *LTable {
200	v := ls.Get(n)
201	if v == LNil {
202		return d
203	}
204	if lv, ok := v.(*LTable); ok {
205		return lv
206	}
207	ls.TypeError(n, LTTable)
208	return nil
209}
210
211func (ls *LState) OptFunction(n int, d *LFunction) *LFunction {
212	v := ls.Get(n)
213	if v == LNil {
214		return d
215	}
216	if lv, ok := v.(*LFunction); ok {
217		return lv
218	}
219	ls.TypeError(n, LTFunction)
220	return nil
221}
222
223func (ls *LState) OptUserData(n int, d *LUserData) *LUserData {
224	v := ls.Get(n)
225	if v == LNil {
226		return d
227	}
228	if lv, ok := v.(*LUserData); ok {
229		return lv
230	}
231	ls.TypeError(n, LTUserData)
232	return nil
233}
234
235/* }}} */
236
237/* error operations {{{ */
238
239func (ls *LState) ArgError(n int, message string) {
240	ls.RaiseError("bad argument #%v to %v (%v)", n, ls.rawFrameFuncName(ls.currentFrame), message)
241}
242
243func (ls *LState) TypeError(n int, typ LValueType) {
244	ls.RaiseError("bad argument #%v to %v (%v expected, got %v)", n, ls.rawFrameFuncName(ls.currentFrame), typ.String(), ls.Get(n).Type().String())
245}
246
247/* }}} */
248
249/* debug operations {{{ */
250
251func (ls *LState) Where(level int) string {
252	return ls.where(level, false)
253}
254
255/* }}} */
256
257/* table operations {{{ */
258
259func (ls *LState) FindTable(obj *LTable, n string, size int) LValue {
260	names := strings.Split(n, ".")
261	curobj := obj
262	for _, name := range names {
263		if curobj.Type() != LTTable {
264			return LNil
265		}
266		nextobj := ls.RawGet(curobj, LString(name))
267		if nextobj == LNil {
268			tb := ls.CreateTable(0, size)
269			ls.RawSet(curobj, LString(name), tb)
270			curobj = tb
271		} else if nextobj.Type() != LTTable {
272			return LNil
273		} else {
274			curobj = nextobj.(*LTable)
275		}
276	}
277	return curobj
278}
279
280/* }}} */
281
282/* register operations {{{ */
283
284func (ls *LState) RegisterModule(name string, funcs map[string]LGFunction) LValue {
285	tb := ls.FindTable(ls.Get(RegistryIndex).(*LTable), "_LOADED", 1)
286	mod := ls.GetField(tb, name)
287	if mod.Type() != LTTable {
288		newmod := ls.FindTable(ls.Get(GlobalsIndex).(*LTable), name, len(funcs))
289		if newmodtb, ok := newmod.(*LTable); !ok {
290			ls.RaiseError("name conflict for module(%v)", name)
291		} else {
292			for fname, fn := range funcs {
293				newmodtb.RawSetString(fname, ls.NewFunction(fn))
294			}
295			ls.SetField(tb, name, newmodtb)
296			return newmodtb
297		}
298	}
299	return mod
300}
301
302func (ls *LState) SetFuncs(tb *LTable, funcs map[string]LGFunction, upvalues ...LValue) *LTable {
303	for fname, fn := range funcs {
304		tb.RawSetString(fname, ls.NewClosure(fn, upvalues...))
305	}
306	return tb
307}
308
309/* }}} */
310
311/* metatable operations {{{ */
312
313func (ls *LState) NewTypeMetatable(typ string) *LTable {
314	regtable := ls.Get(RegistryIndex)
315	mt := ls.GetField(regtable, typ)
316	if tb, ok := mt.(*LTable); ok {
317		return tb
318	}
319	mtnew := ls.NewTable()
320	ls.SetField(regtable, typ, mtnew)
321	return mtnew
322}
323
324func (ls *LState) GetMetaField(obj LValue, event string) LValue {
325	return ls.metaOp1(obj, event)
326}
327
328func (ls *LState) GetTypeMetatable(typ string) LValue {
329	return ls.GetField(ls.Get(RegistryIndex), typ)
330}
331
332func (ls *LState) CallMeta(obj LValue, event string) LValue {
333	op := ls.metaOp1(obj, event)
334	if op.Type() == LTFunction {
335		ls.reg.Push(op)
336		ls.reg.Push(obj)
337		ls.Call(1, 1)
338		return ls.reg.Pop()
339	}
340	return LNil
341}
342
343/* }}} */
344
345/* load and function call operations {{{ */
346
347func (ls *LState) LoadFile(path string) (*LFunction, error) {
348	var file *os.File
349	var err error
350	if len(path) == 0 {
351		file = os.Stdin
352	} else {
353		file, err = os.Open(path)
354		defer file.Close()
355		if err != nil {
356			return nil, newApiErrorE(ApiErrorFile, err)
357		}
358	}
359
360	reader := bufio.NewReader(file)
361	// get the first character.
362	c, err := reader.ReadByte()
363	if err != nil && err != io.EOF {
364		return nil, newApiErrorE(ApiErrorFile, err)
365	}
366	if c == byte('#') {
367		// Unix exec. file?
368		// skip first line
369		_, err, _ = readBufioLine(reader)
370		if err != nil {
371			return nil, newApiErrorE(ApiErrorFile, err)
372		}
373	}
374
375	if err != io.EOF {
376		// if the file is not empty,
377		// unread the first character of the file or newline character(readBufioLine's last byte).
378		err = reader.UnreadByte()
379		if err != nil {
380			return nil, newApiErrorE(ApiErrorFile, err)
381		}
382	}
383
384	return ls.Load(reader, path)
385}
386
387func (ls *LState) LoadString(source string) (*LFunction, error) {
388	return ls.Load(strings.NewReader(source), "<string>")
389}
390
391func (ls *LState) DoFile(path string) error {
392	if fn, err := ls.LoadFile(path); err != nil {
393		return err
394	} else {
395		ls.Push(fn)
396		return ls.PCall(0, MultRet, nil)
397	}
398}
399
400func (ls *LState) DoString(source string) error {
401	if fn, err := ls.LoadString(source); err != nil {
402		return err
403	} else {
404		ls.Push(fn)
405		return ls.PCall(0, MultRet, nil)
406	}
407}
408
409/* }}} */
410
411/* GopherLua original APIs {{{ */
412
413// ToStringMeta returns string representation of given LValue.
414// This method calls the `__tostring` meta method if defined.
415func (ls *LState) ToStringMeta(lv LValue) LValue {
416	if fn, ok := ls.metaOp1(lv, "__tostring").assertFunction(); ok {
417		ls.Push(fn)
418		ls.Push(lv)
419		ls.Call(1, 1)
420		return ls.reg.Pop()
421	} else {
422		return LString(lv.String())
423	}
424}
425
426// Set a module loader to the package.preload table.
427func (ls *LState) PreloadModule(name string, loader LGFunction) {
428	preload := ls.GetField(ls.GetField(ls.Get(EnvironIndex), "package"), "preload")
429	if _, ok := preload.(*LTable); !ok {
430		ls.RaiseError("package.preload must be a table")
431	}
432	ls.SetField(preload, name, ls.NewFunction(loader))
433}
434
435// Checks whether the given index is an LChannel and returns this channel.
436func (ls *LState) CheckChannel(n int) chan LValue {
437	v := ls.Get(n)
438	if ch, ok := v.(LChannel); ok {
439		return (chan LValue)(ch)
440	}
441	ls.TypeError(n, LTChannel)
442	return nil
443}
444
445// If the given index is a LChannel, returns this channel. If this argument is absent or is nil, returns ch. Otherwise, raises an error.
446func (ls *LState) OptChannel(n int, ch chan LValue) chan LValue {
447	v := ls.Get(n)
448	if v == LNil {
449		return ch
450	}
451	if ch, ok := v.(LChannel); ok {
452		return (chan LValue)(ch)
453	}
454	ls.TypeError(n, LTChannel)
455	return nil
456}
457
458/* }}} */
459
460//
461