pcsx-redux/third_party/lua-protobuf/toplevel.lua
Nicolas Pixel Noble f506f642f5 Adding lua-protobuf
2022-12-18 23:05:47 -08:00

478 lines
13 KiB
Lua

--lualoader, R"EOF(--
local string = string
local tonumber = tonumber
local setmetatable = setmetatable
local error = error
local ipairs = ipairs
local io = io
local table = table
local math = math
local assert = assert
local tostring = tostring
local type = type
local insert_tab = table.insert
local function meta(name, t)
t = t or {}
t.__name = name
t.__index = t
return t
end
local function default(t, k, def)
local v = t[k]
if not v then
v = def or {}
t[k] = v
end
return v
end
local toplevel = {} do
local labels = { optional = 1; required = 2; repeated = 3 }
local key_types = {
int32 = 5; int64 = 3; uint32 = 13;
uint64 = 4; sint32 = 17; sint64 = 18;
fixed32 = 7; fixed64 = 6; sfixed32 = 15;
sfixed64 = 16; bool = 8; string = 9;
}
local com_types = {
group = 10; message = 11; enum = 14;
}
local types = {
double = 1; float = 2; int32 = 5;
int64 = 3; uint32 = 13; uint64 = 4;
sint32 = 17; sint64 = 18; fixed32 = 7;
fixed64 = 6; sfixed32 = 15; sfixed64 = 16;
bool = 8; string = 9; bytes = 12;
group = 10; message = 11; enum = 14;
}
local function register_type(self, lex, tname, typ)
if not tname:match "%."then
tname = self.prefix..tname
end
if self.typemap[tname] then
return lex:error("type %s already defined", tname)
end
self.typemap[tname] = typ
end
local function type_info(lex, tname)
local tenum = types[tname]
if com_types[tname] then
return lex:error("invalid type name: "..tname)
elseif tenum then
tname = nil
end
return tenum, tname
end
local function map_info(lex)
local keyt = lex:ident "key type"
if not key_types[keyt] then
return lex:error("invalid key type: "..keyt)
end
local valt = lex:expected "," :type_name()
local name = lex:expected ">" :ident()
local ident = name:gsub("^%a", string.upper)
:gsub("_(%a)", string.upper).."Entry"
local kt, ktn = type_info(lex, keyt)
local vt, vtn = type_info(lex, valt)
return name, types.message, ident, {
name = ident,
field = {
{
name = "key",
number = 1;
label = labels.optional,
type = kt,
type_name = ktn
},
{
name = "value",
number = 2;
label = labels.optional,
type = vt,
type_name = vtn
},
},
options = { map_entry = true }
}
end
local function inline_option(lex, info)
if lex:test "%[" then
info = info or {}
while true do
local name = lex:option_name()
local value = lex:expected '=' :constant()
info[name] = value
if lex:test "%]" then
return info
end
lex:expected ','
end
end
end
local function field(self, lex, ident)
local name, typ, type_name, map_entry
if ident == "map" and lex:test "%<" then
name, typ, type_name, map_entry = map_info(lex)
self.locmap[map_entry.field[1]] = lex.pos
self.locmap[map_entry.field[2]] = lex.pos
register_type(self, lex, type_name, types.message)
else
typ, type_name = type_info(lex, ident)
name = lex:ident()
end
local info = {
name = name,
number = lex:expected "=":integer(),
label = ident == "map" and labels.repeated or labels.optional,
type = typ,
type_name = type_name
}
local options = inline_option(lex)
if options then
info.default_value, options.default = tostring(options.default), nil
info.json_name, options.json_name = options.json_name, nil
if options.packed and options.packed == "false" then
options.packed = false
end
info.options = options
end
if info.number <= 0 then
lex:error("invalid tag number: "..info.number)
end
return info, map_entry
end
local function label_field(self, lex, ident, parent)
local label = labels[ident]
local info, map_entry
if not label then
if self.syntax == "proto2" and ident ~= "map" then
return lex:error("proto2 disallow missing label")
end
return field(self, lex, ident)
end
local proto3_optional = label == labels.optional and self.syntax == "proto3"
if proto3_optional and not (self.proto3_optional and parent) then
return lex:error("proto3 disallow 'optional' label")
end
info, map_entry = field(self, lex, lex:type_name())
if proto3_optional then
local ot = default(parent, "oneof_decl")
info.oneof_index = #ot
ot[#ot+1] = { name = "optional_" .. info.name }
else
info.label = label
end
return info, map_entry
end
function toplevel:package(lex, info)
local package = lex:full_ident 'package name'
lex:line_end()
info.package = package
self.prefix = "."..package.."."
return self
end
function toplevel:import(lex, info)
local mode = lex:ident('"weak" or "public"', 'opt') or "public"
if mode ~= 'weak' and mode ~= 'public' then
return lex:error '"weak or "public" expected'
end
local name = lex:quote()
lex:line_end()
local result = self:parsefile(name)
if self.on_import then
self.on_import(result)
end
local dep = default(info, 'dependency')
local index = #dep
dep[index+1] = name
if mode == "public" then
local it = default(info, 'public_dependency')
insert_tab(it, index)
else
local it = default(info, 'weak_dependency')
insert_tab(it, index)
end
end
local msgbody = {} do
function msgbody:message(lex, info)
local nested_type = default(info, 'nested_type')
insert_tab(nested_type, toplevel.message(self, lex))
return self
end
function msgbody:enum(lex, info)
local nested_type = default(info, 'enum_type')
insert_tab(nested_type, toplevel.enum(self, lex))
return self
end
function msgbody:extend(lex, info)
local extension = default(info, 'extension')
local nested_type = default(info, 'nested_type')
local ft, mt = toplevel.extend(self, lex, {})
for _, v in ipairs(ft) do
insert_tab(extension, v)
end
for _, v in ipairs(mt) do
insert_tab(nested_type, v)
end
return self
end
function msgbody:extensions(lex, info)
local rt = default(info, 'extension_range')
local idx = #rt
repeat
local start = lex:integer "field number range"
local stop = math.floor(2^29)
if lex:keyword('to', 'opt') then
if not lex:keyword('max', 'opt') then
stop = lex:integer "field number range end or 'max'"
end
insert_tab(rt, { start = start, ['end'] = stop })
else
insert_tab(rt, { start = start, ['end'] = start })
end
until not lex:test ','
rt[idx+1].options = inline_option(lex)
lex:line_end()
return self
end
function msgbody:reserved(lex, info)
lex:whitespace()
if not lex '^%d' then
local rt = default(info, 'reserved_name')
repeat
insert_tab(rt, (lex:quote()))
until not lex:test ','
else
local rt = default(info, 'reserved_range')
local first = true
repeat
local start = lex:integer(first and 'field name or number range'
or 'field number range')
if lex:keyword('to', 'opt') then
if lex:keyword('max', 'opt') then
insert_tab(rt, { start = start, ['end'] = 2^29-1 })
else
local stop = lex:integer 'field number range end'
insert_tab(rt, { start = start, ['end'] = stop })
end
else
insert_tab(rt, { start = start, ['end'] = start })
end
first = false
until not lex:test ','
end
lex:line_end()
return self
end
function msgbody:oneof(lex, info)
local fs = default(info, "field")
local ts = default(info, "nested_type")
local ot = default(info, "oneof_decl")
local index = #ot + 1
local oneof = { name = lex:ident() }
lex:expected "{"
while not lex:test "}" do
local ident = lex:type_name()
if ident == "option" then
toplevel.option(self, lex, oneof)
else
local f, t = field(self, lex, ident)
self.locmap[f] = lex.pos
if t then insert_tab(ts, t) end
f.oneof_index = index - 1
insert_tab(fs, f)
end
lex:line_end 'opt'
end
ot[index] = oneof
end
function msgbody:option(lex, info)
toplevel.option(self, lex, info)
end
end
function toplevel:message(lex, info)
local name = lex:ident 'message name'
local typ = { name = name }
register_type(self, lex, name, types.message)
local prefix = self.prefix
self.prefix = prefix..name.."."
lex:expected "{"
while not lex:test "}" do
local ident, pos = lex:type_name()
local body_parser = msgbody[ident]
if body_parser then
body_parser(self, lex, typ)
else
local fs = default(typ, 'field')
local f, t = label_field(self, lex, ident, typ)
self.locmap[f] = pos
insert_tab(fs, f)
if t then
local ts = default(typ, 'nested_type')
insert_tab(ts, t)
end
end
lex:line_end 'opt'
end
lex:line_end 'opt'
if info then
info = default(info, 'message_type')
insert_tab(info, typ)
end
self.prefix = prefix
return typ
end
function toplevel:enum(lex, info)
local name, pos = lex:ident 'enum name'
local enum = { name = name }
self.locmap[enum] = pos
register_type(self, lex, name, types.enum)
lex:expected "{"
while not lex:test "}" do
local ident, pos = lex:ident 'enum constant name'
if ident == 'option' then
toplevel.option(self, lex, enum)
elseif ident == 'reserved' then
msgbody.reserved(self, lex, enum)
else
local values = default(enum, 'value')
local number = lex:expected '=' :integer()
local value = {
name = ident,
number = number,
options = inline_option(lex)
}
self.locmap[value] = pos
insert_tab(values, value)
end
lex:line_end 'opt'
end
lex:line_end 'opt'
if info then
info = default(info, 'enum_type')
insert_tab(info, enum)
end
return enum
end
function toplevel:option(lex, info)
local ident = lex:option_name()
lex:expected "="
local value = lex:constant()
lex:line_end()
local options = info and default(info, 'options') or {}
options[ident] = value
return options, self
end
function toplevel:extend(lex, info)
local name = lex:type_name()
local ft = info and default(info, 'extension') or {}
local mt = info and default(info, 'message_type') or {}
lex:expected "{"
while not lex:test "}" do
local ident, pos = lex:type_name()
local f, t = label_field(self, lex, ident)
self.locmap[f] = pos
f.extendee = name
insert_tab(ft, f)
insert_tab(mt, t)
lex:line_end 'opt'
end
return ft, mt
end
local svr_body = {} do
function svr_body:rpc(lex, info)
local name, pos = lex:ident "rpc name"
local rpc = { name = name }
self.locmap[rpc] = pos
local _, tn
lex:expected "%("
rpc.client_streaming = lex:keyword("stream", "opt")
_, tn = type_info(lex, lex:type_name())
if not tn then return lex:error "rpc input type must by message" end
rpc.input_type = tn
lex:expected "%)" :expected "returns" :expected "%("
rpc.server_streaming = lex:keyword("stream", "opt")
_, tn = type_info(lex, lex:type_name())
if not tn then return lex:error "rpc output type must by message" end
rpc.output_type = tn
lex:expected "%)"
if lex:test "{" then
while not lex:test "}" do
lex:line_end "opt"
lex:keyword "option"
toplevel.option(self, lex, rpc)
end
end
lex:line_end "opt"
local t = default(info, "method")
insert_tab(t, rpc)
end
function svr_body:option(lex, info)
return toplevel.option(self, lex, info)
end
function svr_body.stream(_, lex)
lex:error "stream not implement yet"
end
end
function toplevel:service(lex, info)
local name, pos = lex:ident 'service name'
local svr = { name = name }
self.locmap[svr] = pos
lex:expected "{"
while not lex:test "}" do
local ident = lex:type_name()
local body_parser = svr_body[ident]
if body_parser then
body_parser(self, lex, svr)
else
return lex:error "expected 'rpc' or 'option' in service body"
end
lex:line_end 'opt'
end
lex:line_end 'opt'
if info then
info = default(info, 'service')
insert_tab(info, svr)
end
return svr
end
end
return toplevel
-- )EOF"