aboutsummaryrefslogtreecommitdiff
path: root/mkconvert.lua
diff options
context:
space:
mode:
authorElias Fleckenstein <eliasfleckenstein@web.de>2022-05-28 15:00:35 +0200
committerElias Fleckenstein <eliasfleckenstein@web.de>2022-05-28 15:00:35 +0200
commita0c85883fb541f4b4daab0cf30b4ed2fa7e23262 (patch)
treeb3979ca5832cc2d282b549a784d97df83a60b4c7 /mkconvert.lua
downloadhydra-dragonfire-a0c85883fb541f4b4daab0cf30b4ed2fa7e23262.tar.xz
Initial commit
Diffstat (limited to 'mkconvert.lua')
-rwxr-xr-xmkconvert.lua201
1 files changed, 201 insertions, 0 deletions
diff --git a/mkconvert.lua b/mkconvert.lua
new file mode 100755
index 0000000..d49d46d
--- /dev/null
+++ b/mkconvert.lua
@@ -0,0 +1,201 @@
+#!/usr/bin/env lua
+local function parse_pair(pair, value_first)
+ if pair:sub(1, 1) == "#" then
+ return
+ end
+
+ local idx = pair:find(" ")
+
+ if idx then
+ local first, second = pair:sub(1, idx - 1), pair:sub(idx + 1)
+
+ if value_first and first:sub(1, 1) ~= "[" then
+ return second, first
+ else
+ return first, second
+ end
+ else
+ return pair
+ end
+end
+
+local function parse_spec(name, value_first)
+ local f = io.open("spec/" .. name, "r")
+ local spec = {}
+ local top
+
+ for l in f:lines() do
+ if l:sub(1, 1) == "\t" then
+ local key, val = parse_pair(l:sub(2), value_first)
+
+ if val then
+ top[key] = val
+ elseif key then
+ table.insert(top, key)
+ end
+ else
+ local key, val = parse_pair(l, value_first)
+
+ if val then
+ spec[key] = val
+ elseif key then
+ top = {}
+ spec[key] = top
+ end
+ end
+ end
+
+ f:close()
+ return spec
+end
+
+local casemap = parse_spec("casemap")
+
+local function camel_case(snake)
+ if casemap[snake] then
+ return casemap[snake]
+ end
+
+ local camel = ""
+
+ while #snake > 0 do
+ local idx = snake:find("_") or #snake + 1
+
+ camel = camel
+ .. snake:sub(1, 1):upper()
+ .. snake:sub(2, idx - 1)
+
+ snake = snake:sub(idx + 1)
+ end
+
+ return camel
+end
+
+local funcs = ""
+
+for name, fields in pairs(parse_spec("client/enum")) do
+ local camel = camel_case(name)
+ funcs = funcs .. "func luaPush" .. camel .. "(l *lua.State, val mt." .. camel .. ") {\n\tswitch val {\n"
+
+ for _, var in ipairs(fields) do
+ funcs = funcs .. "\tcase mt."
+ .. (fields.prefix or "") .. camel_case(var) .. (fields.postfix or "")
+ .. ":\n\t\t" .. (var == "no" and "l.PushNil()" or "l.PushString(\"" .. var .. "\")") .. "\n"
+ end
+
+ funcs = funcs .. "\t}\n}\n\n"
+end
+
+for name, fields in pairs(parse_spec("client/flag")) do
+ local camel = camel_case(name)
+ funcs = funcs .. "func luaPush" .. camel .. "(l *lua.State, val mt." .. camel .. ") {\n\tl.NewTable()\n"
+
+ for _, var in ipairs(fields) do
+ funcs = funcs .. "\tif val&mt."
+ .. (fields.prefix or "") .. camel_case(var) .. (fields.postfix or "")
+ .. " != 0 {\n\t\tl.PushBoolean(true)\n\t\tl.SetField(-2, \"" .. var .. "\")\n\t}\n"
+ end
+
+ funcs = funcs .. "}\n\n"
+end
+
+local push_type = {
+ string = "l.PushString(string(VAL))",
+ fixed_string = "l.PushString(string(VAL[:]))",
+ boolean = "l.PushBoolean(bool(VAL))",
+ integer = "l.PushInteger(int(VAL))",
+ number = "l.PushNumber(float64(VAL))",
+ vec2 = "luaPushVec2(l, [2]float64{float64(VAL[0]), float64(VAL[1])})",
+ vec3 = "luaPushVec3(l, [3]float64{float64(VAL[0]), float64(VAL[1]), float64(VAL[2])})",
+ box1 = "luaPushBox1(l, [2]float64{float64(VAL[0]), float64(VAL[1])})",
+ box2 = "luaPushBox2(l, [2][2]float64{{float64(VAL[0][0]), float64(VAL[0][1])}, {float64(VAL[1][0]), float64(VAL[1][1])}})",
+ box3 = "luaPushBox3(l, [2][3]float64{{float64(VAL[0][0]), float64(VAL[0][1]), float64(VAL[0][2])}, {float64(VAL[1][0]), float64(VAL[1][1]), float64(VAL[1][2])}})",
+}
+
+local function push_fields(fields, indent)
+ local impl = ""
+
+ for name, type in pairs(fields) do
+ if name:sub(1, 1) ~= "[" then
+ local camel = "val." .. camel_case(name)
+
+ local idt = indent
+ local condition = fields["[" .. name .. "]"]
+
+ if condition then
+ impl = impl .. indent .. "if " .. condition .. " {\n"
+ idt = idt .. "\t"
+ end
+
+ if push_type[type] then
+ impl = impl .. idt .. push_type[type]:gsub("VAL", camel) .. "\n"
+ else
+ impl = impl .. idt .. "luaPush" .. camel_case(type) .. "(l, " .. camel .. ")\n"
+ end
+
+ impl = impl .. idt .. "l.SetField(-2, \"" .. name .. "\")\n"
+
+ if condition then
+ impl = impl .. indent .. "}\n"
+ end
+ end
+ end
+
+ return impl
+end
+
+for name, fields in pairs(parse_spec("client/struct", true)) do
+ local camel = camel_case(name)
+ funcs = funcs
+ .. "func luaPush" .. camel .. "(l *lua.State, val mt." .. camel .. ") {\n\tl.NewTable()\n"
+ .. push_fields(fields, "\t")
+ .. "}\n\n"
+end
+
+local to_string_impl = ""
+local to_lua_impl = ""
+
+for name, fields in pairs(parse_spec("client/pkt", true)) do
+ local case = "\tcase *mt.ToClt" .. camel_case(name) .. ":\n"
+
+ to_string_impl = to_string_impl
+ .. case .. "\t\treturn \"" .. name .. "\"\n"
+
+ if next(fields) then
+ to_lua_impl = to_lua_impl .. case .. push_fields(fields, "\t\t")
+ end
+end
+
+local f = io.open("convert.go", "w")
+f:write([[
+// generated by mkconvert.lua, DO NOT EDIT
+package main
+
+import (
+ "github.com/Shopify/go-lua"
+ "github.com/anon55555/mt"
+)
+
+]] .. funcs .. [[
+func pktToString(pkt *mt.Pkt) string {
+ switch pkt.Cmd.(type) {
+]] .. to_string_impl .. [[
+ }
+ panic("impossible")
+ return ""
+}
+
+func pktToLua(l *lua.State, pkt *mt.Pkt) {
+ if pkt == nil {
+ l.PushNil()
+ return
+ }
+ l.NewTable()
+ l.PushString(pktToString(pkt))
+ l.SetField(-2, "_type")
+ switch val := pkt.Cmd.(type) {
+]] .. to_lua_impl .. [[
+ }
+}
+]])
+f:close()