Alex Roitman b55300b729 Lua scripting feature. (#224)
* Start on lua scripting

* Implement evalsha, script load, script exists, and script flush

* Type conversions from lua to resp/json.
Refactor to make luastate and luascripts persistent in the controller.

* Change controller.command and all underlying commands to return resp.Value.
Serialize only during the ouput.

* First stab at tile38 call from lua

* Change tile38 into tile38.call in Lua

* Property return errors from scripts

* Minor refactoring.  No locking on script run

* Cleanup/refactoring

* Create a pool of 5 lua states, allow for more as needed. Refactor.

* Use safe map for scripts.  Add a limit for max number of lua states.  Refactor.

* Refactor

* Refactor script commands into atomic, read-only, and non-atomic classes.
Proper locking for all three classes.
Add tests for scripts

* More tests for scripts

* Properly escape newlines in lua-produced errors

* Better test for readonly failure

* Correctly convert ok/err messages between lua and resp.
Add pcall, sha1hex, error_reply, status_reply functions to tile38 namespace in lua.

* Add pcall test. Change writeErr to work with string argument

* Make sure eval/evalsha never attempt to write AOF

* Add eval-set and eval-get to benchmarks

* Fix eval benchmark tests, add more

* Improve benchmarks

* Optimizations and refactoring.

* Add lua memtest

* Typo

* Add dependency

* golint fixes

* gofmt fixes

* Add scripting commands to the core/commands.json

* Use ARGV for args inside lua
2017-10-05 08:20:40 -07:00

97 lines
1.7 KiB
Go

package lua
import (
"sort"
)
func OpenTable(L *LState) int {
tabmod := L.RegisterModule(TabLibName, tableFuncs)
L.Push(tabmod)
return 1
}
var tableFuncs = map[string]LGFunction{
"getn": tableGetN,
"concat": tableConcat,
"insert": tableInsert,
"maxn": tableMaxN,
"remove": tableRemove,
"sort": tableSort,
}
func tableSort(L *LState) int {
tbl := L.CheckTable(1)
sorter := lValueArraySorter{L, nil, tbl.array}
if L.GetTop() != 1 {
sorter.Fn = L.CheckFunction(2)
}
sort.Sort(sorter)
return 0
}
func tableGetN(L *LState) int {
L.Push(LNumber(L.CheckTable(1).Len()))
return 1
}
func tableMaxN(L *LState) int {
L.Push(LNumber(L.CheckTable(1).MaxN()))
return 1
}
func tableRemove(L *LState) int {
tbl := L.CheckTable(1)
if L.GetTop() == 1 {
L.Push(tbl.Remove(-1))
} else {
L.Push(tbl.Remove(L.CheckInt(2)))
}
return 1
}
func tableConcat(L *LState) int {
tbl := L.CheckTable(1)
sep := LString(L.OptString(2, ""))
i := L.OptInt(3, 1)
j := L.OptInt(4, tbl.Len())
if L.GetTop() == 3 {
if i > tbl.Len() || i < 1 {
L.Push(LString(""))
return 1
}
}
i = intMax(intMin(i, tbl.Len()), 1)
j = intMin(intMin(j, tbl.Len()), tbl.Len())
if i > j {
L.Push(LString(""))
return 1
}
//TODO should flushing?
retbottom := L.GetTop()
for ; i <= j; i++ {
L.Push(tbl.RawGetInt(i))
if i != j {
L.Push(sep)
}
}
L.Push(stringConcat(L, L.GetTop()-retbottom, L.reg.Top()-1))
return 1
}
func tableInsert(L *LState) int {
tbl := L.CheckTable(1)
nargs := L.GetTop()
if nargs == 1 {
L.RaiseError("wrong number of arguments")
}
if L.GetTop() == 2 {
tbl.Append(L.Get(2))
return 0
}
tbl.Insert(int(L.CheckInt(2)), L.CheckAny(3))
return 0
}
//