]> git.lizzy.rs Git - hydra-dragonfire.git/blob - mkconvert.lua
d49d46deaa17094e60ce1d9067b869b0c96fa9e2
[hydra-dragonfire.git] / mkconvert.lua
1 #!/usr/bin/env lua
2 local function parse_pair(pair, value_first)
3         if pair:sub(1, 1) == "#" then
4                 return
5         end
6
7         local idx = pair:find(" ")
8
9         if idx then
10                 local first, second = pair:sub(1, idx - 1), pair:sub(idx + 1)
11
12                 if value_first and first:sub(1, 1) ~= "[" then
13                         return second, first
14                 else
15                         return first, second
16                 end
17         else
18                 return pair
19         end
20 end
21
22 local function parse_spec(name, value_first)
23         local f = io.open("spec/" .. name, "r")
24         local spec = {}
25         local top
26
27         for l in f:lines() do
28                 if l:sub(1, 1) == "\t" then
29                         local key, val = parse_pair(l:sub(2), value_first)
30
31                         if val then
32                                 top[key] = val
33                         elseif key then
34                                 table.insert(top, key)
35                         end
36                 else
37                         local key, val = parse_pair(l, value_first)
38
39                         if val then
40                                 spec[key] = val
41                         elseif key then
42                                 top = {}
43                                 spec[key] = top
44                         end
45                 end
46         end
47
48         f:close()
49         return spec
50 end
51
52 local casemap = parse_spec("casemap")
53
54 local function camel_case(snake)
55         if casemap[snake] then
56                 return casemap[snake]
57         end
58
59         local camel = ""
60
61         while #snake > 0 do
62                 local idx = snake:find("_") or #snake + 1
63
64                 camel = camel
65                         .. snake:sub(1, 1):upper()
66                         .. snake:sub(2, idx - 1)
67
68                 snake = snake:sub(idx + 1)
69         end
70
71         return camel
72 end
73
74 local funcs = ""
75
76 for name, fields in pairs(parse_spec("client/enum")) do
77         local camel = camel_case(name)
78         funcs = funcs .. "func luaPush" .. camel .. "(l *lua.State, val mt." .. camel .. ") {\n\tswitch val {\n"
79
80         for _, var in ipairs(fields) do
81                 funcs = funcs .. "\tcase mt."
82                         .. (fields.prefix or "") .. camel_case(var) .. (fields.postfix or "")
83                         .. ":\n\t\t" .. (var == "no" and "l.PushNil()" or "l.PushString(\"" .. var .. "\")") .. "\n"
84         end
85
86         funcs = funcs .. "\t}\n}\n\n"
87 end
88
89 for name, fields in pairs(parse_spec("client/flag")) do
90         local camel = camel_case(name)
91         funcs = funcs .. "func luaPush" .. camel .. "(l *lua.State, val mt." .. camel .. ") {\n\tl.NewTable()\n"
92
93         for _, var in ipairs(fields)    do
94                 funcs = funcs .. "\tif val&mt."
95                         .. (fields.prefix or "") .. camel_case(var) .. (fields.postfix or "")
96                         .. " != 0 {\n\t\tl.PushBoolean(true)\n\t\tl.SetField(-2, \"" .. var  .. "\")\n\t}\n"
97         end
98
99         funcs = funcs .. "}\n\n"
100 end
101
102 local push_type = {
103         string = "l.PushString(string(VAL))",
104         fixed_string = "l.PushString(string(VAL[:]))",
105         boolean = "l.PushBoolean(bool(VAL))",
106         integer = "l.PushInteger(int(VAL))",
107         number = "l.PushNumber(float64(VAL))",
108         vec2 = "luaPushVec2(l, [2]float64{float64(VAL[0]), float64(VAL[1])})",
109         vec3 = "luaPushVec3(l, [3]float64{float64(VAL[0]), float64(VAL[1]), float64(VAL[2])})",
110         box1 = "luaPushBox1(l, [2]float64{float64(VAL[0]), float64(VAL[1])})",
111         box2 = "luaPushBox2(l, [2][2]float64{{float64(VAL[0][0]), float64(VAL[0][1])}, {float64(VAL[1][0]), float64(VAL[1][1])}})",
112         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])}})",
113 }
114
115 local function push_fields(fields, indent)
116         local impl = ""
117         
118         for name, type in pairs(fields) do
119                 if name:sub(1, 1) ~= "[" then
120                         local camel = "val." .. camel_case(name)
121
122                         local idt = indent
123                         local condition = fields["[" .. name .. "]"]
124
125                         if condition then
126                                 impl = impl .. indent .. "if " .. condition .. " {\n" 
127                                 idt = idt .. "\t"
128                         end
129
130                         if push_type[type] then
131                                 impl = impl .. idt .. push_type[type]:gsub("VAL", camel) .. "\n"
132                         else
133                                 impl = impl .. idt .. "luaPush" .. camel_case(type) .. "(l, " .. camel .. ")\n"
134                         end
135
136                         impl = impl .. idt .. "l.SetField(-2, \"" .. name .. "\")\n"
137
138                         if condition then
139                                 impl = impl .. indent .. "}\n"
140                         end
141                 end
142         end
143
144         return impl
145 end
146
147 for name, fields in pairs(parse_spec("client/struct", true)) do
148         local camel = camel_case(name)
149         funcs = funcs
150                 .. "func luaPush" .. camel .. "(l *lua.State, val mt." .. camel .. ") {\n\tl.NewTable()\n"
151                 .. push_fields(fields, "\t")
152                 .. "}\n\n"
153 end
154
155 local to_string_impl = ""
156 local to_lua_impl = ""
157
158 for name, fields in pairs(parse_spec("client/pkt", true)) do
159         local case = "\tcase *mt.ToClt" .. camel_case(name) .. ":\n"
160
161         to_string_impl = to_string_impl
162                 .. case .. "\t\treturn \"" .. name .. "\"\n"
163
164         if next(fields) then
165                 to_lua_impl = to_lua_impl .. case .. push_fields(fields, "\t\t")
166         end
167 end
168
169 local f = io.open("convert.go", "w")
170 f:write([[
171 // generated by mkconvert.lua, DO NOT EDIT
172 package main
173
174 import (
175         "github.com/Shopify/go-lua"
176         "github.com/anon55555/mt"
177 )
178
179 ]] .. funcs .. [[
180 func pktToString(pkt *mt.Pkt) string {
181         switch pkt.Cmd.(type) {
182 ]] .. to_string_impl .. [[
183         }
184         panic("impossible")
185         return ""
186 }
187
188 func pktToLua(l *lua.State, pkt *mt.Pkt) {
189         if pkt == nil {
190                 l.PushNil()
191                 return
192         }
193         l.NewTable()
194         l.PushString(pktToString(pkt))
195         l.SetField(-2, "_type")
196         switch val := pkt.Cmd.(type) {
197 ]] .. to_lua_impl .. [[
198         }
199 }
200 ]])
201 f:close()