Skip to content

Commit

Permalink
Merge pull request #4 from cyanidle/main
Browse files Browse the repository at this point in the history
Upgrade to describe 3.0
  • Loading branch information
cyanidle authored Dec 17, 2024
2 parents b40f9e9 + d7dc915 commit 4ac79bd
Show file tree
Hide file tree
Showing 7 changed files with 170 additions and 106 deletions.
2 changes: 0 additions & 2 deletions cmake/RPCXXCodegen.cmake
Original file line number Diff line number Diff line change
Expand Up @@ -153,12 +153,10 @@ function(rpcxx_codegen ARG_SPEC)

set(output_stem ${prefix}/${output_stem})
set(output ${output_stem}.hpp)
set(byprod ${output_stem}.private.hpp)
set_property(SOURCE ${output} PROPERTY GENERATED 1)

add_custom_command(
OUTPUT ${output}
BYPRODUCTS ${byprod}
COMMAND ${RPCXX_CODE_GENERATOR}
ARGS ${ARG_SPEC} --output-dir ${prefix} ${kwargs}
DEPENDS ${ARG_SPEC} ${_if_codegen_target} ${_scanned_deps}
Expand Down
23 changes: 11 additions & 12 deletions codegen/include/codegen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -29,6 +29,7 @@ SOFTWARE.
#include <fmt/core.h>
#include <fmt/args.h>
#include <fmt/compile.h>
#include <set>
#include <string>
#include <string_view>
#include <filesystem>
Expand Down Expand Up @@ -117,11 +118,19 @@ struct Builtin {
Kind kind;
};

struct Attr {
std::string name;
bool operator<(Attr const& r) const noexcept {
return name < r.name;
}
};

struct Enum : TypeBase {
struct Value {
string name;
std::optional<int64_t> number;
};
std::set<Attr> attributes;
vector<Value> values;
};

Expand All @@ -131,6 +140,7 @@ struct Struct : TypeBase {
Type type = nullptr;
size_t sz = 0;
};
std::set<Attr> attributes;
vector<Field> fields;
};

Expand Down Expand Up @@ -193,20 +203,9 @@ struct Variant : public std::variant<Nil, Int, Num, String, Bool, Table, Array>

}

struct Attr {
std::string name;
std::vector<def::Value>* args;
bool operator<(Attr const& r) const noexcept {
return name < r.name;
}
~Attr() {
if (args) delete args;
}
};

struct WithAttrs : TypeBase {
Type item;
std::vector<Attr> attributes;
std::set<Attr> attributes;
};

struct WithDefault : TypeBase {
Expand Down
79 changes: 56 additions & 23 deletions codegen/include/cpp/typegen.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -3,7 +3,7 @@
/*
Copyright 2024 "NEOLANT Service", "NEOLANT Kalinigrad", Alexey Doronin, Anastasia Lugovets, Dmitriy Dyakonov
Permission is hereby granted, free of charge, to any person obtaining a copy
Permission is hereby granted, free of charge, to any person obtaining enumType copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
Expand Down Expand Up @@ -180,6 +180,34 @@ static string getDefault(Type t) {
});
}

static std::pair<string, string> getAttrNsAndName(string_view attr) {
auto pos = attr.find_last_of('.');
string ns;
string_view name{attr};
if (pos != string::npos) {
ns = ToNamespace(string_view{attr}.substr(0, pos));
name = string_view{attr}.substr(pos + 1);
}
if (ns.empty()) {
return {{}, string{name}};
} else {
return {std::move(ns), string{name}};
}
}

static string formatAttrs(std::set<Attr> const& attrs) {
string res;
for (auto& a: attrs) {
auto [ns, name] = getAttrNsAndName(a.name);
if (ns.empty()) {
res += ", " + name;
} else {
res += ", " + ns + "::" + name;
}
}
return res;
}

static string formatSingleType(FormatContext& ctx, Type t)
{
return Visit(t->AsVariant(),
Expand All @@ -190,11 +218,11 @@ static string formatSingleType(FormatContext& ctx, Type t)
fmt::arg("aliased_type", PrintType(a.item))
);
},
[&](const Enum& a) {
[&](const Enum& enumType) {
string fields;
string field_names;
unsigned count = 0;
for (auto& v: a.values) {
for (auto& v: enumType.values) {
if (auto& n = v.number) {
fields += fmt::format(FMT_COMPILE("\n {} = {},"), v.name, *n);
} else {
Expand All @@ -206,18 +234,18 @@ static string formatSingleType(FormatContext& ctx, Type t)
}
return fmt::format(
enum_fmt,
fmt::arg("ns", ToNamespace(a.ns.name)),
fmt::arg("ns", ToNamespace(enumType.ns.name)),
fmt::arg("type_name", rawName(t)),
fmt::arg("fields", fields),
fmt::arg("cls_attrs", ""),
fmt::arg("cls_attrs", formatAttrs(enumType.attributes)),
fmt::arg("field_names", field_names)
);
},
[&](Struct const& s) {
[&](Struct const& structT) {
string fields;
string field_names;
unsigned count = 0;
for (auto& it: s.fields) {
for (auto& it: structT.fields) {
auto& subName = it.name;
auto& subType = it.type;
fields += fmt::format(
Expand All @@ -228,20 +256,18 @@ static string formatSingleType(FormatContext& ctx, Type t)
);
string fieldAttrs;
if (auto all = as<WithAttrs>(subType)) {
for (auto& a: all->attributes) {
fieldAttrs += ", " + a.name;
}
fieldAttrs = formatAttrs(all->attributes);
}
field_names += fmt::format(
FMT_COMPILE("\n MEMBER(\"{0}\", &_::{0}{1});"),
subName, fieldAttrs);
}
return fmt::format(
struct_fmt,
fmt::arg("ns", ToNamespace(s.ns.name)),
fmt::arg("ns", ToNamespace(structT.ns.name)),
fmt::arg("type_name", rawName(t)),
fmt::arg("fields", fields),
fmt::arg("cls_attrs", ""),
fmt::arg("cls_attrs", formatAttrs(structT.attributes)),
fmt::arg("field_names", field_names)
);
},
Expand Down Expand Up @@ -354,40 +380,47 @@ static void reorderMembers(Struct& t) {
});
}

static void collectAttrs(Type t, std::set<Attr*>& out) {
struct AttrsPtrCmp {
bool operator()(const Attr* l, const Attr* r) const noexcept {
return l->name < r->name;
}
};

using AttrsSet = std::set<const Attr*, AttrsPtrCmp>;

static void collectAttrs(Type t, AttrsSet& out) {
Visit(
t->AsVariant(),
[&](Struct& s){
for (auto& f: s.fields) {
collectAttrs(f.type, out);
}
for (auto& a: s.attributes) {
out.insert(&a);
}
},
[&](WithAttrs& s){
for (auto& a: s.attributes) {
out.insert(&a);
}
},
[&](Enum& s){
// no attrs for enum yet
for (auto& a: s.attributes) {
out.insert(&a);
}
},
[](Builtin){},
[&](auto& s){
collectAttrs(s.item, out);
});
}

static void forwardDeclareAttrs(std::set<Attr*> const& attrs, string& result) {
static void forwardDeclareAttrs(AttrsSet const& attrs, string& result) {
if (attrs.size()) {
result += "\n//Attributes forward declarations: \n";
}
for (auto& a: attrs) {
auto pos = a->name.find_last_of('.');
string_view ns;
string_view name{a->name};
if (pos != string::npos) {
ns = ToNamespace(string_view{a->name}.substr(0, pos));
name = string_view{a->name}.substr(pos + 1);
}
auto [ns, name] = getAttrNsAndName(a->name);
if (ns.empty()) {
result += fmt::format(FMT_COMPILE("\nstruct {};"), name);
} else {
Expand All @@ -406,7 +439,7 @@ std::string Format(FormatContext& ctx)
if (!(ctx.params.targets & TargetTypes))
return "";
std::vector<DepPair> byDepth;
std::set<Attr*> attrs;
AttrsSet attrs;
for (auto& t: ctx.ast.types) {
auto* asStruct = std::get_if<Struct>(&t->AsVariant());
if (asStruct) {
Expand Down
114 changes: 68 additions & 46 deletions codegen/src/codegen.lua.h
Original file line number Diff line number Diff line change
Expand Up @@ -41,13 +41,17 @@ local function make_value(t, ...)
return res
end

local function make_attrs(t, ...)
local attrs = {...}
local function validate_attrs(attrs)
for i, v in ipairs(attrs) do
if type(v) ~= "string" and type(v) ~= "table" then
error(":attrs(): Attribute #"..i.." is not a string or a table!")
end
end
end

local function make_attrs(t, ...)
local attrs = {...}
validate_attrs(attrs)
if #attrs == 0 then return t end
local parent = t
if t.__subtype__ == "attrs" then
Expand Down Expand Up @@ -430,62 +434,80 @@ end
function struct(opts)
check_ns()
opts = init_opts(opts)
return in_strict(function(shape)
local check = function(s, shape)
assert(type(shape) == "table", "struct default value should be table")
local res = {}
for k, v in pairs(s.__fields__) do
if shape[k] then
if not v.__check__ then
error("Field of struct: "..k.." ("..tostring(v)..") does not support default values")
return setmetatable({
attrs = function(self, ...)
self.__attrs__ = {...}
validate_attrs(self.__attrs__)
return self
end
}, {
__call = in_strict(function(self, shape)
local check = function(s, shape)
assert(type(shape) == "table", "struct default value should be table")
local res = {}
for k, v in pairs(s.__fields__) do
if shape[k] then
if not v.__check__ then
error("Field of struct: "..k.." ("..tostring(v)..") does not support default values")
end
res[k] = v:__check__(shape[k])
end
res[k] = v:__check__(shape[k])
end
return res
end
return res
end
local res = make_type(opts.name, nil, check)
assert(type(shape) == "table", '{field = t, ...} expected for struct()')
res.__subtype__ = "struct"
res.__fields__ = {}
for k, v in pairs(shape) do
if not is_priv(k) then
res.__fields__[k] = resolve_type(v, k)
local res = make_type(opts.name, nil, check)
assert(type(shape) == "table", '{field = t, ...} expected for struct()')
res.__subtype__ = "struct"
res.__fields__ = {}
res.__attrs__ = self.__attrs__ or {}
for k, v in pairs(shape) do
if not is_priv(k) then
res.__fields__[k] = resolve_type(v, k)
end
end
end
return res
end)
return res
end)
})
end

function enum(opts)
check_ns()
opts = init_opts(opts)
return in_strict(function(values)
assert(type(values) == "table", '{name, name2, ...} expected for enum()')
local check = function(s, v)
assert(type(v) == "string", "enum default value should be a string")
for i, f in ipairs(s.__fields__) do
if f == v then
return v
return setmetatable({
attrs = function(self, ...)
self.__attrs__ = {...}
validate_attrs(self.__attrs__)
return self
end
}, {
__call = in_strict(function(self, values)
assert(type(values) == "table", '{name, name2, ...} expected for enum()')
local check = function(s, v)
assert(type(v) == "string", "enum default value should be a string")
for i, f in ipairs(s.__fields__) do
if f == v then
return v
end
end
error(v.." is not a valid member of "..tostring(s))
end
error(v.." is not a valid member of "..tostring(s))
end
local res = make_type(opts.name, nil, check)
res.__subtype__ = "enum"
res.__fields__ = values
for k, v in pairs(values) do
if type(k) == "number" then
assert(type(k) == "number", "Enum keys should be integers")
assert(type(v) == "string", "Enum values should be strings")
else
assert(type(k) == "string", "Strict Enum keys should be strings")
assert(type(v) == "number", "Strict Enum values should be integers")
local res = make_type(opts.name, nil, check)
res.__subtype__ = "enum"
res.__fields__ = values
res.__attrs__ = self.__attrs__ or {}
for k, v in pairs(values) do
if type(k) == "number" then
assert(type(k) == "number", "Enum keys should be integers")
assert(type(v) == "string", "Enum values should be strings")
else
assert(type(k) == "string", "Strict Enum keys should be strings")
assert(type(v) == "number", "Strict Enum values should be integers")
end
res[k] = v
end
res[k] = v
end
return res
end)
return res
end)
})
end

function routes(opts)
Expand Down
Loading

0 comments on commit 4ac79bd

Please sign in to comment.