big merge

This commit is contained in:
Philippe G
2021-12-18 21:04:23 -08:00
parent 955692f8ad
commit 898998efb0
583 changed files with 84472 additions and 1965 deletions

View File

@@ -0,0 +1,6 @@
.vscode
protoc-gen-cpprefl
generator/
`
out/
protos/

View File

@@ -0,0 +1,7 @@
# Running
```sh
$ go build -o protoc-gen-cpprefl . && protoc --plugin=protoc-gen-cpprefl=protoc-gen-cpprefl --cpprefl_out okon protos/*.proto --proto_path protos/
```
Will get protos from `protos/` and output to `out/protobuf.h`

View File

@@ -0,0 +1,21 @@
package main
type AliasType struct {
Of GeneratableType
cppType string
}
func (at *AliasType) IdentifierName() string {
return at.Of.IdentifierName()
}
func (at *AliasType) CppType() string {
return at.cppType
}
func (at *AliasType) WriteDeclarations(gen *CppGenerator) {
}
func (at *AliasType) WriteReflection(gen *CppGenerator) {
}

View File

@@ -0,0 +1,192 @@
package main
import (
"fmt"
"log"
"text/template"
)
func GenerateAnyTypes(gen *CppGenerator, primitiveTypes []GeneratableType, allTypes []GeneratableType) {
exceptionalTypes := []GeneratableType{}
allTypesWithoutAliases := []GeneratableType{}
for _, t := range allTypes {
_, isPrimitve := t.(*PrimitiveType)
_, isEnum := t.(*EnumType)
_, isGeneric := t.(GenericType)
if isPrimitve || isEnum || isGeneric {
exceptionalTypes = append(exceptionalTypes, t)
}
if _, ok := t.(*AliasType); !ok {
log.Printf("%#v", t)
allTypesWithoutAliases = append(allTypesWithoutAliases, t)
}
}
template.Must(template.New("any.cpp").Parse(`
class AnyRef {
public:
ReflectTypeID typeID;
AnyRef() {};
AnyRef(ReflectTypeID typeID, void *obj) {
this->typeID = typeID;
this->value.voidptr = obj;
}
template<typename T>
T *as() {
// if(T::_TYPE_ID != this->typeID) {
// throw "invalid as call";
// }
return (T*) this->value.voidptr;
}
template<typename T>
bool is() {
{{range .PrimitiveTypes}}if constexpr(std::is_same<T, {{.CppType}}>::value) {
return ReflectTypeID::{{.IdentifierName}} == this->typeID;
} else
{{end}} {
return T::_TYPE_ID == this->typeID;
}
}
ReflectType *reflectType();
AnyRef getField(int i);
template <typename T>
static AnyRef of(T *obj)
{
ReflectTypeID typeID;
{{range .PrimitiveTypes}}if constexpr(std::is_same<T, {{.CppType}}>::value) {
typeID = ReflectTypeID::{{.IdentifierName}};
} else
{{end}} {
typeID = T::_TYPE_ID;
}
AnyRef a;
a.typeID = typeID;
a.value.voidptr = (void*) obj;
return a;
}
union ReflectedTypes {
void *voidptr;
{{range .allTypes}}{{.CppType}} *u_{{.IdentifierName}};
{{end}}
} value;
private:
};
`)).Execute(gen.Body, map[string]interface{}{
"PrimitiveTypes": exceptionalTypes,
"allTypes": allTypesWithoutAliases,
})
}
func GenerateAnyTypesImplementation(gen *CppGenerator) {
fmt.Fprintf(gen.SubFile("AnyRefImpl.cpp", false).AddLocalInclude(gen.Filename).Body, `
ReflectType *AnyRef::reflectType() {
return &reflectTypeInfo[static_cast<int>(this->typeID)];
}
AnyRef AnyRef::getField(int i) {
auto info = this->reflectType();
if(info->kind != ReflectTypeKind::Class) {
throw "not a class";
}
return AnyRef(info->fields[i].typeID, static_cast<char *>(this->value.voidptr) + info->fields[i].offset);
}
`)
fmt.Fprintf(gen.Body, `
class UniqueAny: public AnyRef {
public:
UniqueAny() {
this->value.voidptr = nullptr;
};
UniqueAny(ReflectTypeID typeID) {
this->typeID = typeID;
auto typeInfo = &reflectTypeInfo[static_cast<int>(typeID)];
AnyRef a;
this->value.voidptr = new unsigned char[typeInfo->size];
typeInfo->_Construct(this->value.voidptr);
};
~UniqueAny() {
auto typeInfo = &reflectTypeInfo[static_cast<int>(typeID)];
typeInfo->_Destruct(this->value.voidptr);
delete reinterpret_cast<char *>(this->value.voidptr);
};
};
class AnyVectorRef {
public:
AnyRef ref;
AnyVectorRef(AnyRef r): ref(r) {}
void push_back(AnyRef &v) {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
typeInfo->vectorOps.push_back(ref, v);
}
size_t size() {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
return typeInfo->vectorOps.size(ref);
}
void emplace_back() {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
typeInfo->vectorOps.emplace_back(ref);
}
void clear() {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
typeInfo->vectorOps.clear(ref);
}
void reserve(size_t n) {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
typeInfo->vectorOps.reserve(ref, n);
}
AnyRef at(size_t index) {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
return typeInfo->vectorOps.at(ref, index);
}
};
class AnyOptionalRef {
public:
AnyRef ref;
AnyOptionalRef(AnyRef r): ref(r) {}
AnyRef get() {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
return typeInfo->optionalOps.get(ref);
}
bool has_value() {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
return typeInfo->optionalOps.has_value(ref);
}
void set(AnyRef &o) {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
typeInfo->optionalOps.set(ref, o);
}
void reset() {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
typeInfo->optionalOps.reset(ref);
}
void emplaceEmpty() {
auto typeInfo = &reflectTypeInfo[static_cast<int>(this->ref.typeID)];
typeInfo->optionalOps.emplaceEmpty(ref);
}
};
`)
}

View File

@@ -0,0 +1,69 @@
package main
import (
"fmt"
)
type ClassField struct {
Name string
ProtobufTag uint32
Type GeneratableType
}
type ClassType struct {
Name string
Fields []ClassField
AdditionalCode string
AdditionalLibraryIncludes []string
ProtoName string
}
func (ct *ClassType) IdentifierName() string {
return "Class" + ct.Name
}
func (ct *ClassType) CppType() string {
return ct.Name
}
func (et *ClassType) DeclarationOrder() int {
return -10
}
func (ct *ClassType) ForwardDeclaration() string {
return fmt.Sprintf("class %v;", ct.Name)
}
func (ct *ClassType) WriteDeclarations(gen *CppGenerator) {
classSubfile := gen.SubFile(ct.ProtoName+".h", true)
gen.AddLocalInclude(classSubfile.Filename)
for _, f := range ct.Fields {
AddIncludeForType(f.Type, classSubfile)
}
for _, i := range ct.AdditionalLibraryIncludes {
classSubfile.AddLibraryInclude(i)
}
classSubfile.OutputClass(ct.Name, func() {
for _, t := range ct.Fields {
classSubfile.OutputClassField(t.Type.CppType(), t.Name)
}
classSubfile.OutputClassTypeID(ct.IdentifierName())
fmt.Fprint(classSubfile.Body, ct.AdditionalCode)
})
}
func (ct *ClassType) WriteReflection(gen *CppGenerator) {
gen.AddLibraryInclude("vector")
fieldsContents := ""
for _, f := range ct.Fields {
fieldsContents += fmt.Sprintf("ReflectField( /* typeID */ ReflectTypeID::%v, /* name */ %v, /* offset */ offsetof(%v, %v), /* protobuf tag */ %v),\n",
f.Type.IdentifierName(), gen.EscapeCppString(f.Name), ct.CppType(), f.Name, f.ProtobufTag)
}
fmt.Fprintf(gen.Body, `ReflectType::ofClass(
/* mine type id */ ReflectTypeID::%v,
/* name */ %v,
/* fields */ std::move(std::vector<ReflectField>{%v}),
/* size */ sizeof(%v),
__reflectConstruct<%v>,
__reflectDestruct<%v>)`,
ct.IdentifierName(), gen.EscapeCppString(ct.CppType()), fieldsContents, ct.CppType(), ct.CppType(), ct.CppType())
}

View File

@@ -0,0 +1,417 @@
package main
import (
"fmt"
"log"
"reflect"
"strings"
"sort"
"github.com/golang/protobuf/protoc-gen-go/descriptor"
plugin "github.com/golang/protobuf/protoc-gen-go/plugin"
)
type GeneratableType interface {
IdentifierName() string
CppType() string
WriteDeclarations(gen *CppGenerator)
WriteReflection(gen *CppGenerator)
}
type GenericType interface {
GeneratableType
GetInnerType() GeneratableType
}
type ForwardDeclarable interface {
ForwardDeclaration() string
}
type DelcarationOrderable interface {
DeclarationOrder() int
}
type Corntext struct {
CG *CppGenerator
Request *plugin.CodeGeneratorRequest // The input.
Response *plugin.CodeGeneratorResponse // The output.
AllTypes []GeneratableType
PrimitiveTypes map[string]GeneratableType
// types required for reflection
TypeIDEnum GeneratableType
ReflectType GeneratableType
ReflectField GeneratableType
ReflectEnumValue GeneratableType
TypeKindEnum GeneratableType
vectorOfReflectFields GeneratableType
vectorOfReflectEnumValues GeneratableType
}
func NewCorntext() *Corntext {
i64 := &PrimitiveType{identifierName: "Int64", cppType: "int64_t"}
return &Corntext{
Request: new(plugin.CodeGeneratorRequest),
Response: new(plugin.CodeGeneratorResponse),
CG: NewCppGenerator("protobuf.h"),
AllTypes: []GeneratableType{},
PrimitiveTypes: map[string]GeneratableType{
"int": &PrimitiveType{identifierName: "Int", cppType: "int"},
// "unsigned int": &PrimitiveType{identifierName: "UnsignedInt", cppType: "unsigned int"},
"char": &PrimitiveType{identifierName: "Char", cppType: "char"},
"unsigned char": &PrimitiveType{identifierName: "UnsignedChar", cppType: "unsigned char"},
"double": &PrimitiveType{identifierName: "Double", cppType: "double"},
"float": &PrimitiveType{identifierName: "Float", cppType: "float"},
"bool": &PrimitiveType{identifierName: "Bool", cppType: "bool"},
"std::string": &PrimitiveType{identifierName: "String", cppType: "std::string"},
"size_t": &AliasType{Of: i64, cppType: "size_t"},
"int32_t": &PrimitiveType{identifierName: "Int32", cppType: "int32_t"},
"int64_t": i64,
"uint32_t": &PrimitiveType{identifierName: "Uint32", cppType: "uint32_t"},
"uint64_t": &PrimitiveType{identifierName: "Uint64", cppType: "uint64_t"},
"uint8_t": &PrimitiveType{identifierName: "Uint8", cppType: "uint8_t"},
},
}
}
func (c *Corntext) outputTypes() {
c.CG.AddLibraryInclude("utility")
c.CG.AddLibraryInclude("vector")
vht := &VectorHelperTypes{}
oht := &OptionalHelperTypes{}
fmt.Fprintln(c.CG.Body, `
template<class T>
void __reflectConstruct(void *mem) {
new(mem) T;
}
template<class T>
void __reflectDestruct(void *obj) {
((T*) obj)->~T();
}
`)
vht.GenerateVectorOperationsStruct(c.CG)
oht.GenerateOptionalOperationsStruct(c.CG)
for _, t := range c.AllTypes {
if fwd, ok := t.(ForwardDeclarable); ok {
fmt.Fprintf(c.CG.Body, "%v\n", fwd.ForwardDeclaration())
}
}
c.CG.AddLibraryInclude("type_traits")
typesToDeclare := make([]GeneratableType, len(c.AllTypes))
for i := range c.AllTypes {
typesToDeclare[i] = c.AllTypes[i]
}
sort.SliceStable(typesToDeclare, func(i, j int) bool {
var ival, jval int
if orderable, ok := typesToDeclare[i].(DelcarationOrderable); ok {
ival = orderable.DeclarationOrder()
}
if orderable, ok := typesToDeclare[j].(DelcarationOrderable); ok {
jval = orderable.DeclarationOrder()
}
return ival < jval
})
for _, t := range typesToDeclare {
t.WriteDeclarations(c.CG)
}
primitiveList := make([]GeneratableType, 0, len(c.PrimitiveTypes))
for _, pt := range c.PrimitiveTypes {
primitiveList = append(primitiveList, pt)
}
GenerateAnyTypes(c.CG, primitiveList, c.AllTypes)
vht.GenerateVectorManipulator(c.CG)
oht.GenerateOptionalManipulator(c.CG)
c.CG.OutputArrayVariableExtern(c.ReflectType.CppType(), "reflectTypeInfo", len(c.AllTypes))
dataFile := c.CG.SubFile("ReflectTypeInfo.cpp", false).AddLocalInclude(c.CG.Filename)
dataFile.OutputArrayVariable(c.ReflectType.CppType(), "reflectTypeInfo", len(c.AllTypes), func() {
for _, t := range c.AllTypes {
if _, ok := t.(*AliasType); ok {
continue
}
t.WriteReflection(dataFile)
fmt.Fprintf(dataFile.Body, ",\n")
}
})
GenerateAnyTypesImplementation(c.CG)
c.CG.OutputToDirectory("protos/")
}
func (c *Corntext) buildAllTypes() {
c.generateReflectionTypes()
c.AllTypes = append(c.AllTypes,
c.TypeIDEnum,
c.ReflectField,
c.ReflectEnumValue,
c.ReflectType,
c.TypeKindEnum,
c.vectorOfReflectFields,
c.vectorOfReflectEnumValues,
)
for _, t := range c.PrimitiveTypes {
c.AllTypes = append(c.AllTypes, t)
}
c.generateProtobufTypes()
i := 0
for _, t := range c.AllTypes {
if _, ok := t.(*AliasType); ok {
continue
}
c.TypeIDEnum.(*EnumType).Values = append(c.TypeIDEnum.(*EnumType).Values, EnumValue{Name: t.IdentifierName(), Value: fmt.Sprintf("%v", i)})
i++
}
}
func (c *Corntext) generateProtobufTypes() {
var pbType2reflection = map[descriptor.FieldDescriptorProto_Type]GeneratableType{
descriptor.FieldDescriptorProto_TYPE_INT32: c.PrimitiveTypes["int32_t"],
descriptor.FieldDescriptorProto_TYPE_SINT32: c.PrimitiveTypes["int32_t"],
descriptor.FieldDescriptorProto_TYPE_SINT64: c.PrimitiveTypes["int64_t"],
descriptor.FieldDescriptorProto_TYPE_INT64: c.PrimitiveTypes["int64_t"],
descriptor.FieldDescriptorProto_TYPE_UINT32: c.PrimitiveTypes["uint32_t"],
descriptor.FieldDescriptorProto_TYPE_UINT64: c.PrimitiveTypes["uint64_t"],
descriptor.FieldDescriptorProto_TYPE_BOOL: c.PrimitiveTypes["bool"],
descriptor.FieldDescriptorProto_TYPE_BYTES: c.genericOf(NewVectorType, c.PrimitiveTypes["uint8_t"]),
descriptor.FieldDescriptorProto_TYPE_STRING: c.PrimitiveTypes["std::string"],
}
for _, f := range c.Request.ProtoFile {
log.Printf("Doing file %v", *f.Name)
typeMappings := map[string]GeneratableType{}
for _, e := range f.EnumType {
values := make([]EnumValue, 0, len(e.Value))
for _, v := range e.Value {
values = append(values, EnumValue{
Name: *v.Name,
Value: fmt.Sprint(*v.Number),
})
}
log.Printf("name: %v", *f.Name)
et := &EnumType{
Name: *e.Name,
Values: values,
ProtoName: StripExtenstion(*f.Name),
}
typeMappings[*e.Name] = et
c.AllTypes = append(c.AllTypes, et)
}
for _, m := range f.MessageType {
ct := &ClassType{
Name: *m.Name,
ProtoName: StripExtenstion(*f.Name),
}
typeMappings[*m.Name] = ct
c.AllTypes = append(c.AllTypes, ct)
}
for _, m := range f.MessageType {
fields := []ClassField{}
for _, f := range m.Field {
isMessage := *f.Type == descriptor.FieldDescriptorProto_TYPE_MESSAGE
isEnum := *f.Type == descriptor.FieldDescriptorProto_TYPE_ENUM
var fieldType GeneratableType
if isMessage || isEnum {
fqn := strings.Split(*f.TypeName, ".")
className := fqn[1]
fieldType = typeMappings[className]
} else {
primitiveType, ok := pbType2reflection[*f.Type]
if !ok {
log.Fatal("unsupported proto type", (*f.Type).String())
}
fieldType = primitiveType
// log.Printf("%#v == %v", primitiveType, *f.Type)
}
if f.Label != nil && *f.Label == descriptor.FieldDescriptorProto_LABEL_REPEATED {
fieldType = c.genericOf(NewVectorType, fieldType)
} else if f.Label != nil && *f.Label != descriptor.FieldDescriptorProto_LABEL_REQUIRED {
fieldType = c.genericOf(NewOptionalType, fieldType)
}
fields = append(fields, ClassField{
Name: *f.Name,
Type: fieldType,
ProtobufTag: uint32(*f.Number),
})
}
ct := typeMappings[*m.Name].(*ClassType)
ct.Fields = fields
}
}
}
func (c *Corntext) genericOf(constructor func(inner GeneratableType) GenericType, inner GeneratableType) (ret GeneratableType) {
sample := constructor(nil)
for _, t := range c.AllTypes {
if v, ok := t.(GenericType); ok {
if reflect.TypeOf(sample).String() == reflect.TypeOf(v).String() && v.GetInnerType() == inner {
ret = v
}
}
}
if ret == nil {
ret = constructor(inner)
c.AllTypes = append(c.AllTypes, ret)
}
return
}
func (c *Corntext) generateReflectionTypes() {
c.TypeIDEnum = &EnumType{
Name: "ReflectTypeID",
ProtoName: "ReflectionInternal",
Values: []EnumValue{},
}
c.TypeKindEnum = &EnumType{
Name: "ReflectTypeKind",
ProtoName: "ReflectionInternal",
Values: []EnumValue{
{Name: "Primitive", Value: "0"},
{Name: "Enum", Value: "1"},
{Name: "Class", Value: "2"},
{Name: "Vector", Value: "3"},
{Name: "Optional", Value: "4"},
},
}
c.ReflectField = &ClassType{
Name: "ReflectField",
ProtoName: "ReflectionInternal",
Fields: []ClassField{
{"typeID", 0, c.TypeIDEnum},
{"name", 0, c.PrimitiveTypes["std::string"]},
{"offset", 0, c.PrimitiveTypes["size_t"]},
{"protobufTag", 0, c.PrimitiveTypes["uint32_t"]},
},
AdditionalLibraryIncludes: []string{
"string",
},
AdditionalCode: `
ReflectField() {};
ReflectField(ReflectTypeID typeID, std::string name, size_t offset, uint32_t protobufTag) {
this->typeID = typeID;
this->name = name;
this->offset = offset;
this->protobufTag = protobufTag;
}
`,
}
c.ReflectEnumValue = &ClassType{
Name: "ReflectEnumValue",
ProtoName: "ReflectionInternal",
Fields: []ClassField{
{"name", 0, c.PrimitiveTypes["std::string"]},
{"value", 0, c.PrimitiveTypes["int"]},
},
AdditionalLibraryIncludes: []string{
"string",
},
AdditionalCode: `
ReflectEnumValue(){};
ReflectEnumValue( std::string name, int value) {
this->name = name;
this->value = value;
}
`,
}
c.vectorOfReflectFields = &VectorType{
InnerType: c.ReflectField,
}
c.vectorOfReflectEnumValues = &VectorType{
InnerType: c.ReflectEnumValue,
}
c.ReflectType = &ClassType{
Name: "ReflectType",
ProtoName: "ReflectionInternal",
Fields: []ClassField{
{"typeID", 0, c.TypeIDEnum},
{"name", 0, c.PrimitiveTypes["std::string"]},
{"kind", 0, c.TypeKindEnum},
{"size", 0, c.PrimitiveTypes["size_t"]},
{"innerType", 0, c.TypeIDEnum},
{"fields", 0, c.vectorOfReflectFields},
{"enumValues", 0, c.vectorOfReflectEnumValues},
},
AdditionalLibraryIncludes: []string{
"string",
"vector",
},
AdditionalCode: `
void (*_Construct)(void *mem);
void (*_Destruct)(void *obj);
VectorOperations vectorOps;
OptionalOperations optionalOps;
static ReflectType ofPrimitive(ReflectTypeID id, std::string name, size_t size) {
ReflectType t;
t.kind = ReflectTypeKind::Primitive;
t.typeID = id;
t.name = name;
t.size = size;
return t;
}
static ReflectType ofEnum(ReflectTypeID id, std::string name, std::vector<ReflectEnumValue> enumValues, size_t size) {
ReflectType t;
t.kind = ReflectTypeKind::Enum;
t.typeID = id;
t.name = name;
t.size = size;
t.enumValues = enumValues;
return t;
}
static ReflectType ofVector(ReflectTypeID id, ReflectTypeID innerType, size_t size,
VectorOperations vectorOps,
void (*_Construct)(void *mem), void (*_Destruct)(void *obj)) {
ReflectType t;
t.kind = ReflectTypeKind::Vector;
t.typeID = id;
t.innerType = innerType;
t.size = size;
t._Construct = _Construct;
t._Destruct = _Destruct;
t.vectorOps = vectorOps;
return t;
}
static ReflectType ofOptional(ReflectTypeID id, ReflectTypeID innerType, size_t size,
OptionalOperations optionalOps,
void (*_Construct)(void *mem), void (*_Destruct)(void *obj)) {
ReflectType t;
t.kind = ReflectTypeKind::Optional;
t.typeID = id;
t.innerType = innerType;
t.size = size;
t._Construct = _Construct;
t._Destruct = _Destruct;
t.optionalOps = optionalOps;
return t;
}
static ReflectType ofClass(ReflectTypeID id, std::string name, std::vector<ReflectField> fields, size_t size, void (*_Construct)(void *mem), void (*_Destruct)(void *obj)) {
ReflectType t;
t.kind = ReflectTypeKind::Class;
t.name = name;
t.typeID = id;
t.size = size;
t.fields = std::move(fields);
t._Construct = _Construct;
t._Destruct = _Destruct;
return t;
}
`,
}
}

View File

@@ -0,0 +1,165 @@
package main
import (
"bytes"
"encoding/json"
"fmt"
"io"
"os"
"path"
"strings"
"unicode"
)
type CppGenerator struct {
includes []string
files map[string]*CppGenerator
Body *bytes.Buffer
BodyBeforeLocalIncludes *bytes.Buffer
Filename string
IsHeader bool
}
// NewCppGenerator docsy bo ci wywali sie blad xd
func NewCppGenerator(filename string) *CppGenerator {
isHeader := true
if strings.HasSuffix(filename, ".cpp") {
isHeader = false
}
return &CppGenerator{
includes: []string{},
Body: &bytes.Buffer{},
BodyBeforeLocalIncludes: &bytes.Buffer{},
files: make(map[string]*CppGenerator),
Filename: filename,
IsHeader: isHeader,
}
}
func (cg *CppGenerator) SubFile(filename string, isHeader bool) *CppGenerator {
if gen, ok := cg.files[filename]; ok {
return gen
}
gen := NewCppGenerator(filename)
gen.IsHeader = isHeader
gen.files = cg.files
cg.files[filename] = gen
return gen
}
// AddLibraryInclude yes
func (cg *CppGenerator) AddLibraryInclude(name string) *CppGenerator {
resultingLine := fmt.Sprintf("#include <%s>", name)
for _, a := range cg.includes {
if a == resultingLine {
return cg
}
}
cg.includes = append(cg.includes, resultingLine)
return cg
}
func (cg *CppGenerator) AddLocalInclude(name string) *CppGenerator {
resultingLine := fmt.Sprintf("#include \"%s\"", name)
for _, a := range cg.includes {
if a == resultingLine {
return cg
}
}
cg.includes = append(cg.includes, resultingLine)
return cg
}
// OutputClassField yes
func (cg *CppGenerator) OutputClassField(theType string, name string) {
fmt.Fprintf(cg.Body, "%v %v;\n", theType, name)
}
// OutputClassTypeID yes
func (cg *CppGenerator) OutputClassTypeID(theID string) {
fmt.Fprintf(cg.Body, "static constexpr ReflectTypeID _TYPE_ID = ReflectTypeID::%v;\n", theID)
}
// OutputClass yes
func (cg *CppGenerator) OutputClass(name string, cb func()) {
fmt.Fprintf(cg.Body, "class %v {\npublic:\n", name)
cb()
fmt.Fprintf(cg.Body, "};\n\n")
}
// OutputEnumClass
func (cg *CppGenerator) OutputEnumClass(name string, cb func()) {
fmt.Fprintf(cg.Body, "enum class %v {\n", name)
cb()
fmt.Fprintf(cg.Body, "};\n\n")
}
func (cg *CppGenerator) OutputArrayVariable(t string, name string, length int, cb func()) {
fmt.Fprintf(cg.Body, "%v %v[%d] = {\n", t, name, length)
cb()
fmt.Fprintf(cg.Body, "};\n\n")
}
func (cg *CppGenerator) OutputArrayVariableExtern(t string, name string, length int) {
fmt.Fprintf(cg.Body, "extern %v %v[%d];", t, name, length)
}
func (cg *CppGenerator) OutputEnumClassField(name string, value string) {
fmt.Fprintf(cg.Body, "%v", name)
if value != "" {
fmt.Fprintf(cg.Body, " = %v", value)
}
fmt.Fprintf(cg.Body, ",\n")
}
func (cg *CppGenerator) EscapeCppString(str string) string {
d, _ := json.Marshal(str)
return string(d)
}
func (cg *CppGenerator) WriteToWriter(w io.Writer) {
fmt.Fprintf(w, "// THIS CORNFILE IS GENERATED. DO NOT EDIT! 🌽\n")
guardString := "_"
for _, c := range []rune(cg.Filename) {
if unicode.IsUpper(c) {
guardString += "_"
}
if unicode.IsLetter(c) {
guardString += strings.ToUpper(string([]rune{c}))
}
}
if cg.IsHeader {
fmt.Fprintf(w, "#ifndef %v\n", guardString)
fmt.Fprintf(w, "#define %v\n", guardString)
}
for _, a := range cg.includes {
if strings.Contains(a, "<") {
fmt.Fprintf(w, "%v\n", a)
}
}
io.Copy(w, cg.BodyBeforeLocalIncludes)
for _, a := range cg.includes {
if !strings.Contains(a, "<") && a != fmt.Sprintf("#include \"%v\"", cg.Filename) {
fmt.Fprintf(w, "%v\n", a)
}
}
io.Copy(w, cg.Body)
if cg.IsHeader {
fmt.Fprintf(w, "#endif\n")
}
}
func (cg *CppGenerator) OutputToDirectory(dirPath string) {
f, _ := os.Create(path.Join(dirPath, cg.Filename))
defer f.Close()
cg.WriteToWriter(f)
for _, fileToOutput := range cg.files {
f, _ := os.Create(path.Join(dirPath, fileToOutput.Filename))
defer f.Close()
fileToOutput.WriteToWriter(f)
}
}

View File

@@ -0,0 +1,44 @@
package main
import "fmt"
type EnumValue struct {
Name string
Value string
}
type EnumType struct {
Name string
Values []EnumValue
ProtoName string
}
func (et *EnumType) IdentifierName() string {
return "Enum" + et.Name
}
func (et *EnumType) DeclarationOrder() int {
return -20
}
func (et *EnumType) CppType() string {
return et.Name
}
func (et *EnumType) WriteDeclarations(gen *CppGenerator) {
enumSubfile := gen.SubFile(et.ProtoName+".h", true)
gen.AddLocalInclude(enumSubfile.Filename)
enumSubfile.OutputEnumClass(et.Name, func() {
for _, v := range et.Values {
enumSubfile.OutputEnumClassField(v.Name, v.Value)
}
})
}
func (et *EnumType) WriteReflection(gen *CppGenerator) {
enumValues := ""
for _, v := range et.Values {
enumValues += fmt.Sprintf(" ReflectEnumValue(%v, %v),\n", gen.EscapeCppString(v.Name), v.Value)
}
fmt.Fprintf(gen.Body, "ReflectType::ofEnum(/* mine id */ ReflectTypeID::%v, /* name */ %v, /* enum values */ std::move(std::vector<ReflectEnumValue>{%v}), /* size */ sizeof(%v))",
et.IdentifierName(), gen.EscapeCppString(et.CppType()), enumValues, et.CppType())
}

View File

@@ -0,0 +1,21 @@
github.com/celer-network/pb3-gen-sol v1.1.1 h1:MaWWsz17plSDCh538l6QaJQ1cOORqzx82lt/slz9pkM=
github.com/celer-network/pb3-gen-sol v1.1.1/go.mod h1:mJkD650gSksCeWrGLzKfj1nMc7y0cFlP3ZC2qaqOk3g=
github.com/golang/protobuf v1.2.0/go.mod h1:6lQm79b+lXiMfvg/cZm0SGofjICqVBUtrP5yJMmIC1U=
github.com/golang/protobuf v1.4.0-rc.1/go.mod h1:ceaxUfeHdC40wWswd/P6IGgMaK3YpKi5j83Wpe3EHw8=
github.com/golang/protobuf v1.4.0-rc.1.0.20200221234624-67d41d38c208/go.mod h1:xKAWHe0F5eneWXFV3EuXVDTCmh+JuBKY0li0aMyXATA=
github.com/golang/protobuf v1.4.0-rc.2/go.mod h1:LlEzMj4AhA7rCAGe4KMBDvJI+AwstrUpVNzEA03Pprs=
github.com/golang/protobuf v1.4.0-rc.4.0.20200313231945-b860323f09d0/go.mod h1:WU3c8KckQ9AFe+yFwt9sWVRKCVIyN9cPHBJSNnbL67w=
github.com/golang/protobuf v1.4.0/go.mod h1:jodUvKwWbYaEsadDk5Fwe5c77LiNKVO9IDvqG2KuDX0=
github.com/golang/protobuf v1.4.3 h1:JjCZWpVbqXDqFVmTfYWEVTMIYrL/NPdPSCHPJ0T/raM=
github.com/golang/protobuf v1.4.3/go.mod h1:oDoupMAO8OvCJWAcko0GGGIgR6R6ocIYbsSw735rRwI=
github.com/google/go-cmp v0.3.0/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.3.1/go.mod h1:8QqcDgzrUqlUb/G2PQTWiueGozuR1884gddMywk6iLU=
github.com/google/go-cmp v0.4.0/go.mod h1:v8dTdLbMG2kIc/vJvl+f65V22dbkXbowE6jgT/gNBxE=
golang.org/x/xerrors v0.0.0-20191204190536-9bdfabe68543/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0=
google.golang.org/protobuf v0.0.0-20200109180630-ec00e32a8dfd/go.mod h1:DFci5gLYBciE7Vtevhsrf46CRTquxDuWsQurQQe4oz8=
google.golang.org/protobuf v0.0.0-20200221191635-4d8936d0db64/go.mod h1:kwYJMbMJ01Woi6D6+Kah6886xMZcty6N08ah7+eCXa0=
google.golang.org/protobuf v0.0.0-20200228230310-ab0ca4ff8a60/go.mod h1:cfTl7dwQJ+fmap5saPgwCLgHXTUD7jkjRqWcaiX5VyM=
google.golang.org/protobuf v1.20.1-0.20200309200217-e05f789c0967/go.mod h1:A+miEFZTKqfCUM6K7xSMQL9OKL/b6hQv+e19PK+JZNE=
google.golang.org/protobuf v1.21.0/go.mod h1:47Nbq4nVaFHyn7ilMalzfO3qCViNmqZ2kzikPIcrTAo=
google.golang.org/protobuf v1.23.0 h1:4MY060fB1DLGMB/7MBTLnwQUY6+F09GEiz6SsrNqyzM=
google.golang.org/protobuf v1.23.0/go.mod h1:EGpADcykh3NcUnDUJcl1+ZksZNG86OlYog2l/sGQquU=

View File

@@ -0,0 +1,34 @@
package main
import (
"io/ioutil"
"log"
"os"
"github.com/celer-network/pb3-gen-sol/generator"
"google.golang.org/protobuf/proto"
)
func main() {
c := NewCorntext()
data, err := ioutil.ReadAll(os.Stdin)
if err != nil {
generator.Error(err, "reading input")
}
if err := proto.Unmarshal(data, c.Request); err != nil {
generator.Error(err, "parsing input proto")
}
c.buildAllTypes()
c.outputTypes()
// Send back the results.
data, err = proto.Marshal(c.Response)
if err != nil {
log.Fatal(err, "failed to marshal output proto")
}
_, err = os.Stdout.Write(data)
if err != nil {
log.Fatal(err, "failed to write output proto")
}
}

View File

@@ -0,0 +1,53 @@
package main
import "fmt"
type OptionalHelperTypes struct {
}
func (oht *OptionalHelperTypes) GenerateOptionalOperationsStruct(cg *CppGenerator) {
fmt.Fprintln(cg.BodyBeforeLocalIncludes, `
class AnyRef;
struct OptionalOperations {
AnyRef (*get)(AnyRef &opt);
bool (*has_value)(AnyRef &opt);
void (*set)(AnyRef &opt, AnyRef &val);
void (*reset)(AnyRef &opt);
void (*emplaceEmpty)(AnyRef &opt);
};
`)
}
func (oht *OptionalHelperTypes) GenerateOptionalManipulator(cg *CppGenerator) {
fmt.Fprintln(cg.Body, `
template<class T>
class __OptionalManipulator {
public:
static AnyRef get(AnyRef &opt) {
auto theOptional = reinterpret_cast<std::optional<T>*>(opt.value.voidptr);
return AnyRef::of<T>(&**theOptional);
}
static bool has_value(AnyRef &opt) {
auto theOptional = reinterpret_cast<std::optional<T>*>(opt.value.voidptr);
return theOptional->has_value();
}
static void set(AnyRef &opt, AnyRef &val) {
auto theOptional = reinterpret_cast<std::optional<T>*>(opt.value.voidptr);
auto theValue = reinterpret_cast<T*>(val.value.voidptr);
*theOptional = *theValue;
}
static void reset(AnyRef &opt) {
auto theOptional = reinterpret_cast<std::optional<T>*>(opt.value.voidptr);
theOptional->reset();
}
static void emplaceEmpty(AnyRef &opt) {
auto theOptional = reinterpret_cast<std::optional<T>*>(opt.value.voidptr);
theOptional->emplace();
}
};
`)
}

View File

@@ -0,0 +1,54 @@
package main
import (
"fmt"
"text/template"
)
type OptionalType struct {
InnerType GeneratableType
}
func NewOptionalType(inner GeneratableType) GenericType {
return &OptionalType{
InnerType: inner,
}
}
func (vt *OptionalType) GetInnerType() GeneratableType {
return vt.InnerType
}
func (vt *OptionalType) IdentifierName() string {
return "OptionalOf" + vt.InnerType.IdentifierName()
}
func (vt *OptionalType) CppType() string {
return fmt.Sprintf("std::optional<%v>", vt.InnerType.CppType())
}
func (vt *OptionalType) WriteDeclarations(gen *CppGenerator) {
gen.AddLibraryInclude("optional")
}
func (vt *OptionalType) WriteReflection(gen *CppGenerator) {
template.Must(template.New("any.cpp").Parse(`
ReflectType::ofOptional(
/* mine typeId */ ReflectTypeID::{{ .IdentifierName }},
/* inner type id */ ReflectTypeID::{{ .InnerType.IdentifierName }},
/* size */ sizeof({{ .CppType }}),
/* option */ OptionalOperations{
.get = __OptionalManipulator<{{ .InnerType.CppType }}>::get,
.has_value = __OptionalManipulator<{{ .InnerType.CppType }}>::has_value,
.set = __OptionalManipulator<{{ .InnerType.CppType }}>::set,
.reset = __OptionalManipulator<{{ .InnerType.CppType }}>::reset,
.emplaceEmpty = __OptionalManipulator<{{ .InnerType.CppType }}>::emplaceEmpty,
},
__reflectConstruct<{{ .CppType }}>,
__reflectDestruct<{{ .CppType }}>
)
`)).Execute(gen.Body, vt)
}

View File

@@ -0,0 +1,26 @@
package main
import "fmt"
type PrimitiveType struct {
identifierName string
cppType string
}
func (pt *PrimitiveType) IdentifierName() string {
return pt.identifierName
}
func (pt *PrimitiveType) CppType() string {
return pt.cppType
}
func (pt *PrimitiveType) WriteDeclarations(gen *CppGenerator) {
if pt.cppType == "std::string" {
gen.AddLibraryInclude("string")
}
}
func (pt *PrimitiveType) WriteReflection(gen *CppGenerator) {
fmt.Fprintf(gen.Body, "ReflectType::ofPrimitive(/* type id */ ReflectTypeID::%v, /* name */ %v, /* size */ sizeof(%v))",
pt.IdentifierName(), gen.EscapeCppString(pt.CppType()), pt.CppType())
}

View File

@@ -0,0 +1 @@
package main

View File

@@ -0,0 +1,25 @@
package main
import (
"path/filepath"
"strings"
)
func AddIncludeForType(t GeneratableType, gen *CppGenerator) {
switch v := t.(type) {
case *ClassType:
gen.AddLocalInclude(v.ProtoName + ".h")
case *EnumType:
gen.AddLocalInclude(v.ProtoName + ".h")
case *VectorType:
gen.AddLibraryInclude("vector")
AddIncludeForType(v.InnerType, gen)
case *OptionalType:
gen.AddLibraryInclude("optional")
AddIncludeForType(v.InnerType, gen)
}
}
func StripExtenstion(filename string) string {
return strings.TrimSuffix(filename, filepath.Ext(filename))
}

View File

@@ -0,0 +1,55 @@
package main
import "fmt"
type VectorHelperTypes struct {
}
func (vht *VectorHelperTypes) GenerateVectorOperationsStruct(cg *CppGenerator) {
fmt.Fprintln(cg.BodyBeforeLocalIncludes, `
class AnyRef;
struct VectorOperations {
void (*push_back)(AnyRef &vec, AnyRef &val);
AnyRef (*at)(AnyRef &vec, size_t index);
size_t (*size)(AnyRef &vec);
void (*emplace_back)(AnyRef &vec);
void (*clear)(AnyRef &vec);
void (*reserve)(AnyRef &vec, size_t n);
};
`)
}
func (vht *VectorHelperTypes) GenerateVectorManipulator(cg *CppGenerator) {
fmt.Fprintln(cg.Body, `
template<class T>
class __VectorManipulator {
public:
static void push_back(AnyRef &vec, AnyRef &val) {
auto theVector = reinterpret_cast<std::vector<T>*>(vec.value.voidptr);
auto theValue = *reinterpret_cast<T*>(val.value.voidptr);
theVector->push_back(theValue);
};
static AnyRef at(AnyRef &vec, size_t index) {
auto theVector = reinterpret_cast<std::vector<T>*>(vec.value.voidptr);
return AnyRef::of<T>(&(*theVector)[index]);
};
static size_t size(AnyRef &vec) {
auto theVector = reinterpret_cast<std::vector<T>*>(vec.value.voidptr);
return theVector->size();
};
static void emplace_back(AnyRef &vec) {
auto theVector = reinterpret_cast<std::vector<T>*>(vec.value.voidptr);
theVector->emplace_back();
};
static void clear(AnyRef &vec) {
auto theVector = reinterpret_cast<std::vector<T>*>(vec.value.voidptr);
theVector->clear();
};
static void reserve(AnyRef &vec, size_t n) {
auto theVector = reinterpret_cast<std::vector<T>*>(vec.value.voidptr);
theVector->reserve(n);
};
};
`)
}

View File

@@ -0,0 +1,65 @@
package main
import (
"fmt"
"text/template"
)
type VectorType struct {
InnerType GeneratableType
}
func NewVectorType(inner GeneratableType) GenericType {
return &VectorType{
InnerType: inner,
}
}
func (vt *VectorType) GetInnerType() GeneratableType {
return vt.InnerType
}
func (vt *VectorType) IdentifierName() string {
return "VectorOf" + vt.InnerType.IdentifierName()
}
func (vt *VectorType) CppType() string {
return fmt.Sprintf("std::vector<%v>", vt.InnerType.CppType())
}
func (vt *VectorType) WriteDeclarations(gen *CppGenerator) {
gen.AddLibraryInclude("vector")
}
func (vt *VectorType) WriteReflection(gen *CppGenerator) {
template.Must(template.New("any.cpp").Parse(`
ReflectType::ofVector(
/* mine typeId */ ReflectTypeID::{{ .IdentifierName }},
/* inner type id */ ReflectTypeID::{{ .InnerType.IdentifierName }},
/* size */ sizeof({{ .CppType }}),
VectorOperations{
.push_back = __VectorManipulator<{{ .InnerType.CppType }}>::push_back,
.at = __VectorManipulator<{{ .InnerType.CppType }}>::at,
.size = __VectorManipulator<{{ .InnerType.CppType }}>::size,
.emplace_back = __VectorManipulator<{{ .InnerType.CppType }}>::emplace_back,
.clear = __VectorManipulator<{{ .InnerType.CppType }}>::clear,
.reserve = __VectorManipulator<{{ .InnerType.CppType }}>::reserve,
},
__reflectConstruct<{{ .CppType }}>,
__reflectDestruct<{{ .CppType }}>
)
`)).Execute(gen.Body, vt)
// fmt.Fprintf(gen.Body, `ReflectType::ofVector(
// /* mine typeId */ ReflectTypeID::%v,
// /* inner type id */ ReflectTypeID::%v,
// /* size */ sizeof(%v),
// VectorOperations{
// .push_back = __VectorManipulator<%v>
// },
// __reflectConstruct<%v>,
// __reflectDestruct<%v>
// )`,
// vt.IdentifierName(), vt.InnerType.IdentifierName(), vt.CppType(), vt.CppType(), vt.CppType(), vt.CppType())
}