go fmt formatted project

This commit is contained in:
L11R 2018-10-23 15:49:10 +03:00
parent e292b9559e
commit e253c67052
15 changed files with 884 additions and 882 deletions

View file

@ -16,4 +16,6 @@ generate-code:
-functionFile function.go \ -functionFile function.go \
-typeFile type.go \ -typeFile type.go \
-unmarshalerFile unmarshaler.go -unmarshalerFile unmarshaler.go
go fmt ./client
format-project:
go fmt ./...

View file

@ -1,52 +1,52 @@
package puller package puller
import ( import (
"github.com/zelenin/go-tdlib/client" "github.com/zelenin/go-tdlib/client"
) )
func ChatHistory(tdlibClient *client.Client, chatId int64) (chan *client.Message, chan error) { func ChatHistory(tdlibClient *client.Client, chatId int64) (chan *client.Message, chan error) {
messageChan := make(chan *client.Message, 10) messageChan := make(chan *client.Message, 10)
errChan := make(chan error, 1) errChan := make(chan error, 1)
var fromMessageId int64 = 0 var fromMessageId int64 = 0
var offset int32 = 0 var offset int32 = 0
var limit int32 = 100 var limit int32 = 100
go chatHistory(tdlibClient, messageChan, errChan, chatId, fromMessageId, offset, limit, false) go chatHistory(tdlibClient, messageChan, errChan, chatId, fromMessageId, offset, limit, false)
return messageChan, errChan return messageChan, errChan
} }
func chatHistory(tdlibClient *client.Client, messageChan chan *client.Message, errChan chan error, chatId int64, fromMessageId int64, offset int32, limit int32, onlyLocal bool) { func chatHistory(tdlibClient *client.Client, messageChan chan *client.Message, errChan chan error, chatId int64, fromMessageId int64, offset int32, limit int32, onlyLocal bool) {
defer func() { defer func() {
close(messageChan) close(messageChan)
close(errChan) close(errChan)
}() }()
for { for {
messages, err := tdlibClient.GetChatHistory(&client.GetChatHistoryRequest{ messages, err := tdlibClient.GetChatHistory(&client.GetChatHistoryRequest{
ChatId: chatId, ChatId: chatId,
FromMessageId: fromMessageId, FromMessageId: fromMessageId,
Offset: offset, Offset: offset,
Limit: limit, Limit: limit,
OnlyLocal: onlyLocal, OnlyLocal: onlyLocal,
}) })
if err != nil { if err != nil {
errChan <- err errChan <- err
return return
} }
if len(messages.Messages) == 0 { if len(messages.Messages) == 0 {
errChan <- EOP errChan <- EOP
break break
} }
for _, message := range messages.Messages { for _, message := range messages.Messages {
fromMessageId = message.Id fromMessageId = message.Id
messageChan <- message messageChan <- message
} }
} }
} }

View file

@ -1,62 +1,62 @@
package puller package puller
import ( import (
"math" "math"
"github.com/zelenin/go-tdlib/client" "github.com/zelenin/go-tdlib/client"
) )
func Chats(tdlibClient *client.Client) (chan *client.Chat, chan error) { func Chats(tdlibClient *client.Client) (chan *client.Chat, chan error) {
chatChan := make(chan *client.Chat, 10) chatChan := make(chan *client.Chat, 10)
errChan := make(chan error, 1) errChan := make(chan error, 1)
var offsetOrder client.JsonInt64 = math.MaxInt64 var offsetOrder client.JsonInt64 = math.MaxInt64
var offsetChatId int64 = 0 var offsetChatId int64 = 0
var limit int32 = 100 var limit int32 = 100
go chats(tdlibClient, chatChan, errChan, offsetOrder, offsetChatId, limit) go chats(tdlibClient, chatChan, errChan, offsetOrder, offsetChatId, limit)
return chatChan, errChan return chatChan, errChan
} }
func chats(tdlibClient *client.Client, chatChan chan *client.Chat, errChan chan error, offsetOrder client.JsonInt64, offsetChatId int64, limit int32) { func chats(tdlibClient *client.Client, chatChan chan *client.Chat, errChan chan error, offsetOrder client.JsonInt64, offsetChatId int64, limit int32) {
defer func() { defer func() {
close(chatChan) close(chatChan)
close(errChan) close(errChan)
}() }()
for { for {
chats, err := tdlibClient.GetChats(&client.GetChatsRequest{ chats, err := tdlibClient.GetChats(&client.GetChatsRequest{
OffsetOrder: offsetOrder, OffsetOrder: offsetOrder,
OffsetChatId: offsetChatId, OffsetChatId: offsetChatId,
Limit: limit, Limit: limit,
}) })
if err != nil { if err != nil {
errChan <- err errChan <- err
return return
} }
if len(chats.ChatIds) == 0 { if len(chats.ChatIds) == 0 {
errChan <- EOP errChan <- EOP
break break
} }
for _, chatId := range chats.ChatIds { for _, chatId := range chats.ChatIds {
chat, err := tdlibClient.GetChat(&client.GetChatRequest{ chat, err := tdlibClient.GetChat(&client.GetChatRequest{
ChatId: chatId, ChatId: chatId,
}) })
if err != nil { if err != nil {
errChan <- err errChan <- err
return return
} }
offsetOrder = chat.Order offsetOrder = chat.Order
offsetChatId = chat.Id offsetChatId = chat.Id
chatChan <- chat chatChan <- chat
} }
} }
} }

View file

@ -1,7 +1,7 @@
package puller package puller
import ( import (
"errors" "errors"
) )
var EOP = errors.New("end of pull") var EOP = errors.New("end of pull")

View file

@ -1,53 +1,53 @@
package puller package puller
import ( import (
"github.com/zelenin/go-tdlib/client" "github.com/zelenin/go-tdlib/client"
) )
func SupergroupMembers(tdlibClient *client.Client, supergroupId int32) (chan *client.ChatMember, chan error) { func SupergroupMembers(tdlibClient *client.Client, supergroupId int32) (chan *client.ChatMember, chan error) {
chatMemberChan := make(chan *client.ChatMember, 10) chatMemberChan := make(chan *client.ChatMember, 10)
errChan := make(chan error, 1) errChan := make(chan error, 1)
var filter client.SupergroupMembersFilter = nil var filter client.SupergroupMembersFilter = nil
var offset int32 = 0 var offset int32 = 0
var limit int32 = 200 var limit int32 = 200
go supergroupMembers(tdlibClient, chatMemberChan, errChan, supergroupId, filter, offset, limit) go supergroupMembers(tdlibClient, chatMemberChan, errChan, supergroupId, filter, offset, limit)
return chatMemberChan, errChan return chatMemberChan, errChan
} }
func supergroupMembers(tdlibClient *client.Client, chatMemberChan chan *client.ChatMember, errChan chan error, supergroupId int32, filter client.SupergroupMembersFilter, offset int32, limit int32) { func supergroupMembers(tdlibClient *client.Client, chatMemberChan chan *client.ChatMember, errChan chan error, supergroupId int32, filter client.SupergroupMembersFilter, offset int32, limit int32) {
defer func() { defer func() {
close(chatMemberChan) close(chatMemberChan)
close(errChan) close(errChan)
}() }()
var page int32 = 0 var page int32 = 0
for { for {
chatMembers, err := tdlibClient.GetSupergroupMembers(&client.GetSupergroupMembersRequest{ chatMembers, err := tdlibClient.GetSupergroupMembers(&client.GetSupergroupMembersRequest{
SupergroupId: supergroupId, SupergroupId: supergroupId,
Filter: filter, Filter: filter,
Offset: page*limit + offset, Offset: page*limit + offset,
Limit: limit, Limit: limit,
}) })
if err != nil { if err != nil {
errChan <- err errChan <- err
return return
} }
if len(chatMembers.Members) == 0 { if len(chatMembers.Members) == 0 {
errChan <- EOP errChan <- EOP
break break
} }
for _, member := range chatMembers.Members { for _, member := range chatMembers.Members {
chatMemberChan <- member chatMemberChan <- member
} }
page++ page++
} }
} }

View file

@ -1,86 +1,86 @@
package main package main
import ( import (
"bufio" "bufio"
"flag" "flag"
"log" "log"
"net/http" "net/http"
"os" "os"
"path/filepath" "path/filepath"
"github.com/zelenin/go-tdlib/tlparser" "github.com/zelenin/go-tdlib/codegen"
"github.com/zelenin/go-tdlib/codegen" "github.com/zelenin/go-tdlib/tlparser"
) )
type config struct { type config struct {
version string version string
outputDirPath string outputDirPath string
packageName string packageName string
functionFileName string functionFileName string
typeFileName string typeFileName string
unmarshalerFileName string unmarshalerFileName string
} }
func main() { func main() {
var config config var config config
flag.StringVar(&config.version, "version", "", "TDLib version") flag.StringVar(&config.version, "version", "", "TDLib version")
flag.StringVar(&config.outputDirPath, "outputDir", "./tdlib", "output directory") flag.StringVar(&config.outputDirPath, "outputDir", "./tdlib", "output directory")
flag.StringVar(&config.packageName, "package", "tdlib", "package name") flag.StringVar(&config.packageName, "package", "tdlib", "package name")
flag.StringVar(&config.functionFileName, "functionFile", "function.go", "functions filename") flag.StringVar(&config.functionFileName, "functionFile", "function.go", "functions filename")
flag.StringVar(&config.typeFileName, "typeFile", "type.go", "types filename") flag.StringVar(&config.typeFileName, "typeFile", "type.go", "types filename")
flag.StringVar(&config.unmarshalerFileName, "unmarshalerFile", "unmarshaler.go", "unmarshalers filename") flag.StringVar(&config.unmarshalerFileName, "unmarshalerFile", "unmarshaler.go", "unmarshalers filename")
flag.Parse() flag.Parse()
resp, err := http.Get("https://raw.githubusercontent.com/tdlib/td/" + config.version + "/td/generate/scheme/td_api.tl") resp, err := http.Get("https://raw.githubusercontent.com/tdlib/td/" + config.version + "/td/generate/scheme/td_api.tl")
if err != nil { if err != nil {
log.Fatalf("http.Get error: %s", err) log.Fatalf("http.Get error: %s", err)
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
schema, err := tlparser.Parse(resp.Body) schema, err := tlparser.Parse(resp.Body)
if err != nil { if err != nil {
log.Fatalf("schema parse error: %s", err) log.Fatalf("schema parse error: %s", err)
return return
} }
err = os.MkdirAll(config.outputDirPath, 0755) err = os.MkdirAll(config.outputDirPath, 0755)
if err != nil { if err != nil {
log.Fatalf("error creating %s: %s", config.outputDirPath, err) log.Fatalf("error creating %s: %s", config.outputDirPath, err)
} }
functionFilePath := filepath.Join(config.outputDirPath, config.functionFileName) functionFilePath := filepath.Join(config.outputDirPath, config.functionFileName)
os.Remove(functionFilePath) os.Remove(functionFilePath)
functionFile, err := os.OpenFile(functionFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) functionFile, err := os.OpenFile(functionFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("functionFile open error: %s", err) log.Fatalf("functionFile open error: %s", err)
} }
defer functionFile.Close() defer functionFile.Close()
bufio.NewWriter(functionFile).Write(codegen.GenerateFunctions(schema, config.packageName)) bufio.NewWriter(functionFile).Write(codegen.GenerateFunctions(schema, config.packageName))
typeFilePath := filepath.Join(config.outputDirPath, config.typeFileName) typeFilePath := filepath.Join(config.outputDirPath, config.typeFileName)
os.Remove(typeFilePath) os.Remove(typeFilePath)
typeFile, err := os.OpenFile(typeFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) typeFile, err := os.OpenFile(typeFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("typeFile open error: %s", err) log.Fatalf("typeFile open error: %s", err)
} }
defer typeFile.Close() defer typeFile.Close()
bufio.NewWriter(typeFile).Write(codegen.GenerateTypes(schema, config.packageName)) bufio.NewWriter(typeFile).Write(codegen.GenerateTypes(schema, config.packageName))
unmarshalerFilePath := filepath.Join(config.outputDirPath, config.unmarshalerFileName) unmarshalerFilePath := filepath.Join(config.outputDirPath, config.unmarshalerFileName)
os.Remove(unmarshalerFilePath) os.Remove(unmarshalerFilePath)
unmarshalerFile, err := os.OpenFile(unmarshalerFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) unmarshalerFile, err := os.OpenFile(unmarshalerFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("unmarshalerFile open error: %s", err) log.Fatalf("unmarshalerFile open error: %s", err)
} }
defer unmarshalerFile.Close() defer unmarshalerFile.Close()
bufio.NewWriter(unmarshalerFile).Write(codegen.GenerateUnmarshalers(schema, config.packageName)) bufio.NewWriter(unmarshalerFile).Write(codegen.GenerateUnmarshalers(schema, config.packageName))
} }

View file

@ -1,67 +1,67 @@
package main package main
import ( import (
"bufio" "bufio"
"encoding/json" "encoding/json"
"flag" "flag"
"log" "github.com/zelenin/go-tdlib/tlparser"
"net/http" "log"
"os" "net/http"
"path/filepath" "os"
"strings" "path/filepath"
"github.com/zelenin/go-tdlib/tlparser" "strings"
) )
func main() { func main() {
var version string var version string
var outputFilePath string var outputFilePath string
flag.StringVar(&version, "version", "", "TDLib version") flag.StringVar(&version, "version", "", "TDLib version")
flag.StringVar(&outputFilePath, "output", "./td_api.json", "json schema file") flag.StringVar(&outputFilePath, "output", "./td_api.json", "json schema file")
flag.Parse() flag.Parse()
resp, err := http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/generate/scheme/td_api.tl") resp, err := http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/generate/scheme/td_api.tl")
if err != nil { if err != nil {
log.Fatalf("http.Get error: %s", err) log.Fatalf("http.Get error: %s", err)
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
schema, err := tlparser.Parse(resp.Body) schema, err := tlparser.Parse(resp.Body)
if err != nil { if err != nil {
log.Fatalf("schema parse error: %s", err) log.Fatalf("schema parse error: %s", err)
return return
} }
resp, err = http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/telegram/Td.cpp") resp, err = http.Get("https://raw.githubusercontent.com/tdlib/td/" + version + "/td/telegram/Td.cpp")
if err != nil { if err != nil {
log.Fatalf("http.Get error: %s", err) log.Fatalf("http.Get error: %s", err)
return return
} }
defer resp.Body.Close() defer resp.Body.Close()
err = tlparser.ParseCode(resp.Body, schema) err = tlparser.ParseCode(resp.Body, schema)
if err != nil { if err != nil {
log.Fatalf("parse code error: %s", err) log.Fatalf("parse code error: %s", err)
return return
} }
err = os.MkdirAll(filepath.Dir(outputFilePath), os.ModePerm) err = os.MkdirAll(filepath.Dir(outputFilePath), os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("make dir error: %s", filepath.Dir(outputFilePath)) log.Fatalf("make dir error: %s", filepath.Dir(outputFilePath))
} }
file, err := os.OpenFile(outputFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm) file, err := os.OpenFile(outputFilePath, os.O_CREATE|os.O_RDWR|os.O_TRUNC, os.ModePerm)
if err != nil { if err != nil {
log.Fatalf("open file error: %s", err) log.Fatalf("open file error: %s", err)
return return
} }
data, err := json.MarshalIndent(schema, "", strings.Repeat(" ", 4)) data, err := json.MarshalIndent(schema, "", strings.Repeat(" ", 4))
if err != nil { if err != nil {
log.Fatalf("json marshal error: %s", err) log.Fatalf("json marshal error: %s", err)
return return
} }
bufio.NewWriter(file).Write(data) bufio.NewWriter(file).Write(data)
} }

View file

@ -1,83 +1,83 @@
package codegen package codegen
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/zelenin/go-tdlib/tlparser" "github.com/zelenin/go-tdlib/tlparser"
) )
func GenerateFunctions(schema *tlparser.Schema, packageName string) []byte { func GenerateFunctions(schema *tlparser.Schema, packageName string) []byte {
buf := bytes.NewBufferString("") buf := bytes.NewBufferString("")
buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName)) buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName))
buf.WriteString(`import ( buf.WriteString(`import (
"errors" "errors"
)`) )`)
buf.WriteString("\n") buf.WriteString("\n")
for _, function := range schema.Functions { for _, function := range schema.Functions {
tdlibFunction := TdlibFunction(function.Name, schema) tdlibFunction := TdlibFunction(function.Name, schema)
tdlibFunctionReturn := TdlibFunctionReturn(function.Class, schema) tdlibFunctionReturn := TdlibFunctionReturn(function.Class, schema)
if len(function.Properties) > 0 { if len(function.Properties) > 0 {
buf.WriteString("\n") buf.WriteString("\n")
buf.WriteString(fmt.Sprintf("type %sRequest struct { \n", tdlibFunction.ToGoName())) buf.WriteString(fmt.Sprintf("type %sRequest struct { \n", tdlibFunction.ToGoName()))
for _, property := range function.Properties { for _, property := range function.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema) tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
buf.WriteString(fmt.Sprintf(" // %s\n", property.Description)) buf.WriteString(fmt.Sprintf(" // %s\n", property.Description))
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name)) buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name))
} }
buf.WriteString("}\n") buf.WriteString("}\n")
} }
buf.WriteString("\n") buf.WriteString("\n")
buf.WriteString("// " + function.Description) buf.WriteString("// " + function.Description)
buf.WriteString("\n") buf.WriteString("\n")
requestArgument := "" requestArgument := ""
if len(function.Properties) > 0 { if len(function.Properties) > 0 {
requestArgument = fmt.Sprintf("req *%sRequest", tdlibFunction.ToGoName()) requestArgument = fmt.Sprintf("req *%sRequest", tdlibFunction.ToGoName())
} }
buf.WriteString(fmt.Sprintf("func (client *Client) %s(%s) (%s, error) {\n", tdlibFunction.ToGoName(), requestArgument, tdlibFunctionReturn.ToGoReturn())) buf.WriteString(fmt.Sprintf("func (client *Client) %s(%s) (%s, error) {\n", tdlibFunction.ToGoName(), requestArgument, tdlibFunctionReturn.ToGoReturn()))
sendMethod := "Send" sendMethod := "Send"
if function.IsSynchronous { if function.IsSynchronous {
sendMethod = "jsonClient.Execute" sendMethod = "jsonClient.Execute"
} }
if len(function.Properties) > 0 { if len(function.Properties) > 0 {
buf.WriteString(fmt.Sprintf(` result, err := client.%s(Request{ buf.WriteString(fmt.Sprintf(` result, err := client.%s(Request{
meta: meta{ meta: meta{
Type: "%s", Type: "%s",
}, },
Data: map[string]interface{}{ Data: map[string]interface{}{
`, sendMethod, function.Name)) `, sendMethod, function.Name))
for _, property := range function.Properties { for _, property := range function.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema) tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
buf.WriteString(fmt.Sprintf(" \"%s\": req.%s,\n", property.Name, tdlibTypeProperty.ToGoName())) buf.WriteString(fmt.Sprintf(" \"%s\": req.%s,\n", property.Name, tdlibTypeProperty.ToGoName()))
} }
buf.WriteString(` }, buf.WriteString(` },
}) })
`) `)
} else { } else {
buf.WriteString(fmt.Sprintf(` result, err := client.%s(Request{ buf.WriteString(fmt.Sprintf(` result, err := client.%s(Request{
meta: meta{ meta: meta{
Type: "%s", Type: "%s",
}, },
Data: map[string]interface{}{}, Data: map[string]interface{}{},
}) })
`, sendMethod, function.Name)) `, sendMethod, function.Name))
} }
buf.WriteString(` if err != nil { buf.WriteString(` if err != nil {
return nil, err return nil, err
} }
@ -87,29 +87,29 @@ func GenerateFunctions(schema *tlparser.Schema, packageName string) []byte {
`) `)
if tdlibFunctionReturn.IsClass() { if tdlibFunctionReturn.IsClass() {
buf.WriteString(" switch result.Type {\n") buf.WriteString(" switch result.Type {\n")
for _, subType := range tdlibFunctionReturn.GetClass().GetSubTypes() { for _, subType := range tdlibFunctionReturn.GetClass().GetSubTypes() {
buf.WriteString(fmt.Sprintf(` case %s: buf.WriteString(fmt.Sprintf(` case %s:
return Unmarshal%s(result.Data) return Unmarshal%s(result.Data)
`, subType.ToTypeConst(), subType.ToGoType())) `, subType.ToTypeConst(), subType.ToGoType()))
} }
buf.WriteString(` default: buf.WriteString(` default:
return nil, errors.New("invalid type") return nil, errors.New("invalid type")
`) `)
buf.WriteString(" }\n") buf.WriteString(" }\n")
} else { } else {
buf.WriteString(fmt.Sprintf(` return Unmarshal%s(result.Data) buf.WriteString(fmt.Sprintf(` return Unmarshal%s(result.Data)
`, tdlibFunctionReturn.ToGoType())) `, tdlibFunctionReturn.ToGoType()))
} }
buf.WriteString("}\n") buf.WriteString("}\n")
} }
return buf.Bytes() return buf.Bytes()
} }

View file

@ -1,26 +1,26 @@
package codegen package codegen
import ( import (
"strings" "strings"
"unicode" "unicode"
) )
func firstUpper(str string) string { func firstUpper(str string) string {
for i, r := range str { for i, r := range str {
return string(unicode.ToUpper(r)) + str[i+1:] return string(unicode.ToUpper(r)) + str[i+1:]
} }
return str return str
} }
func firstLower(str string) string { func firstLower(str string) string {
for i, r := range str { for i, r := range str {
return string(unicode.ToLower(r)) + str[i+1:] return string(unicode.ToLower(r)) + str[i+1:]
} }
return str return str
} }
func underscoreToCamelCase(s string) string { func underscoreToCamelCase(s string) string {
return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1) return strings.Replace(strings.Title(strings.Replace(strings.ToLower(s), "_", " ", -1)), " ", "", -1)
} }

View file

@ -1,487 +1,487 @@
package codegen package codegen
import ( import (
"github.com/zelenin/go-tdlib/tlparser" "github.com/zelenin/go-tdlib/tlparser"
"strings" "log"
"log" "strings"
) )
type tdlibFunction struct { type tdlibFunction struct {
name string name string
schema *tlparser.Schema schema *tlparser.Schema
} }
func TdlibFunction(name string, schema *tlparser.Schema) *tdlibFunction { func TdlibFunction(name string, schema *tlparser.Schema) *tdlibFunction {
return &tdlibFunction{ return &tdlibFunction{
name: name, name: name,
schema: schema, schema: schema,
} }
} }
func (entity *tdlibFunction) ToGoName() string { func (entity *tdlibFunction) ToGoName() string {
return firstUpper(entity.name) return firstUpper(entity.name)
} }
type tdlibFunctionReturn struct { type tdlibFunctionReturn struct {
name string name string
schema *tlparser.Schema schema *tlparser.Schema
} }
func TdlibFunctionReturn(name string, schema *tlparser.Schema) *tdlibFunctionReturn { func TdlibFunctionReturn(name string, schema *tlparser.Schema) *tdlibFunctionReturn {
return &tdlibFunctionReturn{ return &tdlibFunctionReturn{
name: name, name: name,
schema: schema, schema: schema,
} }
} }
func (entity *tdlibFunctionReturn) IsType() bool { func (entity *tdlibFunctionReturn) IsType() bool {
return isType(entity.name, func(entity *tlparser.Type) string { return isType(entity.name, func(entity *tlparser.Type) string {
return entity.Class return entity.Class
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibFunctionReturn) GetType() *tdlibType { func (entity *tdlibFunctionReturn) GetType() *tdlibType {
return getType(entity.name, func(entity *tlparser.Type) string { return getType(entity.name, func(entity *tlparser.Type) string {
return entity.Class return entity.Class
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibFunctionReturn) IsClass() bool { func (entity *tdlibFunctionReturn) IsClass() bool {
return isClass(entity.name, func(entity *tlparser.Class) string { return isClass(entity.name, func(entity *tlparser.Class) string {
return entity.Name return entity.Name
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibFunctionReturn) GetClass() *tdlibClass { func (entity *tdlibFunctionReturn) GetClass() *tdlibClass {
return getClass(entity.name, func(entity *tlparser.Class) string { return getClass(entity.name, func(entity *tlparser.Class) string {
return entity.Name return entity.Name
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibFunctionReturn) ToGoReturn() string { func (entity *tdlibFunctionReturn) ToGoReturn() string {
if strings.HasPrefix(entity.name, "vector<") { if strings.HasPrefix(entity.name, "vector<") {
log.Fatal("vectors are not supported") log.Fatal("vectors are not supported")
} }
if entity.IsClass() { if entity.IsClass() {
return entity.GetClass().ToGoType() return entity.GetClass().ToGoType()
} }
if entity.GetType().IsInternal() { if entity.GetType().IsInternal() {
return entity.GetType().ToGoType() return entity.GetType().ToGoType()
} }
return "*" + entity.GetType().ToGoType() return "*" + entity.GetType().ToGoType()
} }
func (entity *tdlibFunctionReturn) ToGoType() string { func (entity *tdlibFunctionReturn) ToGoType() string {
if strings.HasPrefix(entity.name, "vector<") { if strings.HasPrefix(entity.name, "vector<") {
log.Fatal("vectors are not supported") log.Fatal("vectors are not supported")
} }
if entity.IsClass() { if entity.IsClass() {
return entity.GetClass().ToGoType() return entity.GetClass().ToGoType()
} }
return entity.GetType().ToGoType() return entity.GetType().ToGoType()
} }
type tdlibFunctionProperty struct { type tdlibFunctionProperty struct {
name string name string
propertyType string propertyType string
schema *tlparser.Schema schema *tlparser.Schema
} }
func TdlibFunctionProperty(name string, propertyType string, schema *tlparser.Schema) *tdlibFunctionProperty { func TdlibFunctionProperty(name string, propertyType string, schema *tlparser.Schema) *tdlibFunctionProperty {
return &tdlibFunctionProperty{ return &tdlibFunctionProperty{
name: name, name: name,
propertyType: propertyType, propertyType: propertyType,
schema: schema, schema: schema,
} }
} }
func (entity *tdlibFunctionProperty) GetPrimitive() string { func (entity *tdlibFunctionProperty) GetPrimitive() string {
primitive := entity.propertyType primitive := entity.propertyType
for strings.HasPrefix(primitive, "vector<") { for strings.HasPrefix(primitive, "vector<") {
primitive = strings.TrimSuffix(strings.TrimPrefix(primitive, "vector<"), ">") primitive = strings.TrimSuffix(strings.TrimPrefix(primitive, "vector<"), ">")
} }
return primitive return primitive
} }
func (entity *tdlibFunctionProperty) IsType() bool { func (entity *tdlibFunctionProperty) IsType() bool {
primitive := entity.GetPrimitive() primitive := entity.GetPrimitive()
return isType(primitive, func(entity *tlparser.Type) string { return isType(primitive, func(entity *tlparser.Type) string {
return entity.Name return entity.Name
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibFunctionProperty) GetType() *tdlibType { func (entity *tdlibFunctionProperty) GetType() *tdlibType {
primitive := entity.GetPrimitive() primitive := entity.GetPrimitive()
return getType(primitive, func(entity *tlparser.Type) string { return getType(primitive, func(entity *tlparser.Type) string {
return entity.Name return entity.Name
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibFunctionProperty) IsClass() bool { func (entity *tdlibFunctionProperty) IsClass() bool {
primitive := entity.GetPrimitive() primitive := entity.GetPrimitive()
return isClass(primitive, func(entity *tlparser.Class) string { return isClass(primitive, func(entity *tlparser.Class) string {
return entity.Name return entity.Name
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibFunctionProperty) GetClass() *tdlibClass { func (entity *tdlibFunctionProperty) GetClass() *tdlibClass {
primitive := entity.GetPrimitive() primitive := entity.GetPrimitive()
return getClass(primitive, func(entity *tlparser.Class) string { return getClass(primitive, func(entity *tlparser.Class) string {
return entity.Name return entity.Name
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibFunctionProperty) ToGoName() string { func (entity *tdlibFunctionProperty) ToGoName() string {
name := firstLower(underscoreToCamelCase(entity.name)) name := firstLower(underscoreToCamelCase(entity.name))
if name == "type" { if name == "type" {
name += "Param" name += "Param"
} }
return name return name
} }
func (entity *tdlibFunctionProperty) ToGoType() string { func (entity *tdlibFunctionProperty) ToGoType() string {
tdlibType := entity.propertyType tdlibType := entity.propertyType
goType := "" goType := ""
for strings.HasPrefix(tdlibType, "vector<") { for strings.HasPrefix(tdlibType, "vector<") {
goType = goType + "[]" goType = goType + "[]"
tdlibType = strings.TrimSuffix(strings.TrimPrefix(tdlibType, "vector<"), ">") tdlibType = strings.TrimSuffix(strings.TrimPrefix(tdlibType, "vector<"), ">")
} }
if entity.IsClass() { if entity.IsClass() {
return goType + entity.GetClass().ToGoType() return goType + entity.GetClass().ToGoType()
} }
if entity.GetType().IsInternal() { if entity.GetType().IsInternal() {
return goType + entity.GetType().ToGoType() return goType + entity.GetType().ToGoType()
} }
return goType + "*" + entity.GetType().ToGoType() return goType + "*" + entity.GetType().ToGoType()
} }
type tdlibType struct { type tdlibType struct {
name string name string
schema *tlparser.Schema schema *tlparser.Schema
} }
func TdlibType(name string, schema *tlparser.Schema) *tdlibType { func TdlibType(name string, schema *tlparser.Schema) *tdlibType {
return &tdlibType{ return &tdlibType{
name: name, name: name,
schema: schema, schema: schema,
} }
} }
func (entity *tdlibType) IsInternal() bool { func (entity *tdlibType) IsInternal() bool {
switch entity.name { switch entity.name {
case "double": case "double":
return true return true
case "string": case "string":
return true return true
case "int32": case "int32":
return true return true
case "int53": case "int53":
return true return true
case "int64": case "int64":
return true return true
case "bytes": case "bytes":
return true return true
case "boolFalse": case "boolFalse":
return true return true
case "boolTrue": case "boolTrue":
return true return true
case "vector<t>": case "vector<t>":
return true return true
} }
return false return false
} }
func (entity *tdlibType) GetType() *tlparser.Type { func (entity *tdlibType) GetType() *tlparser.Type {
name := normalizeEntityName(entity.name) name := normalizeEntityName(entity.name)
for _, typ := range entity.schema.Types { for _, typ := range entity.schema.Types {
if typ.Name == name { if typ.Name == name {
return typ return typ
} }
} }
return nil return nil
} }
func (entity *tdlibType) ToGoType() string { func (entity *tdlibType) ToGoType() string {
if strings.HasPrefix(entity.name, "vector<") { if strings.HasPrefix(entity.name, "vector<") {
log.Fatal("vectors are not supported") log.Fatal("vectors are not supported")
} }
switch entity.name { switch entity.name {
case "double": case "double":
return "float64" return "float64"
case "string": case "string":
return "string" return "string"
case "int32": case "int32":
return "int32" return "int32"
case "int53": case "int53":
return "int64" return "int64"
case "int64": case "int64":
return "JsonInt64" return "JsonInt64"
case "bytes": case "bytes":
return "[]byte" return "[]byte"
case "boolFalse": case "boolFalse":
return "bool" return "bool"
case "boolTrue": case "boolTrue":
return "bool" return "bool"
} }
return firstUpper(entity.name) return firstUpper(entity.name)
} }
func (entity *tdlibType) ToType() string { func (entity *tdlibType) ToType() string {
return entity.ToGoType() + "Type" return entity.ToGoType() + "Type"
} }
func (entity *tdlibType) HasClass() bool { func (entity *tdlibType) HasClass() bool {
className := entity.GetType().Class className := entity.GetType().Class
for _, class := range entity.schema.Classes { for _, class := range entity.schema.Classes {
if class.Name == className { if class.Name == className {
return true return true
} }
} }
return false return false
} }
func (entity *tdlibType) GetClass() *tlparser.Class { func (entity *tdlibType) GetClass() *tlparser.Class {
className := entity.GetType().Class className := entity.GetType().Class
for _, class := range entity.schema.Classes { for _, class := range entity.schema.Classes {
if class.Name == className { if class.Name == className {
return class return class
} }
} }
return nil return nil
} }
func (entity *tdlibType) HasClassProperties() bool { func (entity *tdlibType) HasClassProperties() bool {
for _, prop := range entity.GetType().Properties { for _, prop := range entity.GetType().Properties {
tdlibTypeProperty := TdlibTypeProperty(prop.Name, prop.Type, entity.schema) tdlibTypeProperty := TdlibTypeProperty(prop.Name, prop.Type, entity.schema)
if tdlibTypeProperty.IsClass() && !tdlibTypeProperty.IsList() { if tdlibTypeProperty.IsClass() && !tdlibTypeProperty.IsList() {
return true return true
} }
} }
return false return false
} }
func (entity *tdlibType) IsList() bool { func (entity *tdlibType) IsList() bool {
return strings.HasPrefix(entity.name, "vector<") return strings.HasPrefix(entity.name, "vector<")
} }
func (entity *tdlibType) ToClassConst() string { func (entity *tdlibType) ToClassConst() string {
if entity.HasClass() { if entity.HasClass() {
return "Class" + TdlibClass(entity.GetType().Class, entity.schema).ToGoType() return "Class" + TdlibClass(entity.GetType().Class, entity.schema).ToGoType()
} }
return "Class" + entity.ToGoType() return "Class" + entity.ToGoType()
} }
func (entity *tdlibType) ToTypeConst() string { func (entity *tdlibType) ToTypeConst() string {
return "Type" + entity.ToGoType() return "Type" + entity.ToGoType()
} }
type tdlibClass struct { type tdlibClass struct {
name string name string
schema *tlparser.Schema schema *tlparser.Schema
} }
func TdlibClass(name string, schema *tlparser.Schema) *tdlibClass { func TdlibClass(name string, schema *tlparser.Schema) *tdlibClass {
return &tdlibClass{ return &tdlibClass{
name: name, name: name,
schema: schema, schema: schema,
} }
} }
func (entity *tdlibClass) ToGoType() string { func (entity *tdlibClass) ToGoType() string {
return firstUpper(entity.name) return firstUpper(entity.name)
} }
func (entity *tdlibClass) ToType() string { func (entity *tdlibClass) ToType() string {
return entity.ToGoType() + "Type" return entity.ToGoType() + "Type"
} }
func (entity *tdlibClass) GetSubTypes() []*tdlibType { func (entity *tdlibClass) GetSubTypes() []*tdlibType {
types := []*tdlibType{} types := []*tdlibType{}
for _, t := range entity.schema.Types { for _, t := range entity.schema.Types {
if t.Class == entity.name { if t.Class == entity.name {
types = append(types, TdlibType(t.Name, entity.schema)) types = append(types, TdlibType(t.Name, entity.schema))
} }
} }
return types return types
} }
func (entity *tdlibClass) ToClassConst() string { func (entity *tdlibClass) ToClassConst() string {
return "Class" + entity.ToGoType() return "Class" + entity.ToGoType()
} }
type tdlibTypeProperty struct { type tdlibTypeProperty struct {
name string name string
propertyType string propertyType string
schema *tlparser.Schema schema *tlparser.Schema
} }
func TdlibTypeProperty(name string, propertyType string, schema *tlparser.Schema) *tdlibTypeProperty { func TdlibTypeProperty(name string, propertyType string, schema *tlparser.Schema) *tdlibTypeProperty {
return &tdlibTypeProperty{ return &tdlibTypeProperty{
name: name, name: name,
propertyType: propertyType, propertyType: propertyType,
schema: schema, schema: schema,
} }
} }
func (entity *tdlibTypeProperty) IsList() bool { func (entity *tdlibTypeProperty) IsList() bool {
return strings.HasPrefix(entity.propertyType, "vector<") return strings.HasPrefix(entity.propertyType, "vector<")
} }
func (entity *tdlibTypeProperty) GetPrimitive() string { func (entity *tdlibTypeProperty) GetPrimitive() string {
primitive := entity.propertyType primitive := entity.propertyType
for strings.HasPrefix(primitive, "vector<") { for strings.HasPrefix(primitive, "vector<") {
primitive = strings.TrimSuffix(strings.TrimPrefix(primitive, "vector<"), ">") primitive = strings.TrimSuffix(strings.TrimPrefix(primitive, "vector<"), ">")
} }
return primitive return primitive
} }
func (entity *tdlibTypeProperty) IsType() bool { func (entity *tdlibTypeProperty) IsType() bool {
primitive := entity.GetPrimitive() primitive := entity.GetPrimitive()
return isType(primitive, func(entity *tlparser.Type) string { return isType(primitive, func(entity *tlparser.Type) string {
return entity.Name return entity.Name
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibTypeProperty) GetType() *tdlibType { func (entity *tdlibTypeProperty) GetType() *tdlibType {
primitive := entity.GetPrimitive() primitive := entity.GetPrimitive()
return getType(primitive, func(entity *tlparser.Type) string { return getType(primitive, func(entity *tlparser.Type) string {
return entity.Name return entity.Name
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibTypeProperty) IsClass() bool { func (entity *tdlibTypeProperty) IsClass() bool {
primitive := entity.GetPrimitive() primitive := entity.GetPrimitive()
return isClass(primitive, func(entity *tlparser.Class) string { return isClass(primitive, func(entity *tlparser.Class) string {
return entity.Name return entity.Name
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibTypeProperty) GetClass() *tdlibClass { func (entity *tdlibTypeProperty) GetClass() *tdlibClass {
primitive := entity.GetPrimitive() primitive := entity.GetPrimitive()
return getClass(primitive, func(entity *tlparser.Class) string { return getClass(primitive, func(entity *tlparser.Class) string {
return entity.Name return entity.Name
}, entity.schema) }, entity.schema)
} }
func (entity *tdlibTypeProperty) ToGoName() string { func (entity *tdlibTypeProperty) ToGoName() string {
return firstUpper(underscoreToCamelCase(entity.name)) return firstUpper(underscoreToCamelCase(entity.name))
} }
func (entity *tdlibTypeProperty) ToGoFunctionPropertyName() string { func (entity *tdlibTypeProperty) ToGoFunctionPropertyName() string {
name := firstLower(underscoreToCamelCase(entity.name)) name := firstLower(underscoreToCamelCase(entity.name))
if name == "type" { if name == "type" {
name += "Param" name += "Param"
} }
return name return name
} }
func (entity *tdlibTypeProperty) ToGoType() string { func (entity *tdlibTypeProperty) ToGoType() string {
tdlibType := entity.propertyType tdlibType := entity.propertyType
goType := "" goType := ""
for strings.HasPrefix(tdlibType, "vector<") { for strings.HasPrefix(tdlibType, "vector<") {
goType = goType + "[]" goType = goType + "[]"
tdlibType = strings.TrimSuffix(strings.TrimPrefix(tdlibType, "vector<"), ">") tdlibType = strings.TrimSuffix(strings.TrimPrefix(tdlibType, "vector<"), ">")
} }
if entity.IsClass() { if entity.IsClass() {
return goType + entity.GetClass().ToGoType() return goType + entity.GetClass().ToGoType()
} }
if entity.GetType().IsInternal() { if entity.GetType().IsInternal() {
return goType + entity.GetType().ToGoType() return goType + entity.GetType().ToGoType()
} }
return goType + "*" + entity.GetType().ToGoType() return goType + "*" + entity.GetType().ToGoType()
} }
func isType(name string, field func(entity *tlparser.Type) string, schema *tlparser.Schema) bool { func isType(name string, field func(entity *tlparser.Type) string, schema *tlparser.Schema) bool {
name = normalizeEntityName(name) name = normalizeEntityName(name)
for _, entity := range schema.Types { for _, entity := range schema.Types {
if name == field(entity) { if name == field(entity) {
return true return true
} }
} }
return false return false
} }
func getType(name string, field func(entity *tlparser.Type) string, schema *tlparser.Schema) *tdlibType { func getType(name string, field func(entity *tlparser.Type) string, schema *tlparser.Schema) *tdlibType {
name = normalizeEntityName(name) name = normalizeEntityName(name)
for _, entity := range schema.Types { for _, entity := range schema.Types {
if name == field(entity) { if name == field(entity) {
return TdlibType(entity.Name, schema) return TdlibType(entity.Name, schema)
} }
} }
return nil return nil
} }
func isClass(name string, field func(entity *tlparser.Class) string, schema *tlparser.Schema) bool { func isClass(name string, field func(entity *tlparser.Class) string, schema *tlparser.Schema) bool {
name = normalizeEntityName(name) name = normalizeEntityName(name)
for _, entity := range schema.Classes { for _, entity := range schema.Classes {
if name == field(entity) { if name == field(entity) {
return true return true
} }
} }
return false return false
} }
func getClass(name string, field func(entity *tlparser.Class) string, schema *tlparser.Schema) *tdlibClass { func getClass(name string, field func(entity *tlparser.Class) string, schema *tlparser.Schema) *tdlibClass {
name = normalizeEntityName(name) name = normalizeEntityName(name)
for _, entity := range schema.Classes { for _, entity := range schema.Classes {
if name == field(entity) { if name == field(entity) {
return TdlibClass(entity.Name, schema) return TdlibClass(entity.Name, schema)
} }
} }
return nil return nil
} }
func normalizeEntityName(name string) string { func normalizeEntityName(name string) string {
if name == "Bool" { if name == "Bool" {
name = "boolFalse" name = "boolFalse"
} }
return name return name
} }

View file

@ -1,91 +1,91 @@
package codegen package codegen
import ( import (
"bytes" "bytes"
"fmt" "fmt"
"github.com/zelenin/go-tdlib/tlparser" "github.com/zelenin/go-tdlib/tlparser"
) )
func GenerateTypes(schema *tlparser.Schema, packageName string) []byte { func GenerateTypes(schema *tlparser.Schema, packageName string) []byte {
buf := bytes.NewBufferString("") buf := bytes.NewBufferString("")
buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName)) buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName))
buf.WriteString(`import ( buf.WriteString(`import (
"encoding/json" "encoding/json"
) )
`) `)
buf.WriteString("const (\n") buf.WriteString("const (\n")
for _, entity := range schema.Classes { for _, entity := range schema.Classes {
tdlibClass := TdlibClass(entity.Name, schema) tdlibClass := TdlibClass(entity.Name, schema)
buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibClass.ToClassConst(), entity.Name)) buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibClass.ToClassConst(), entity.Name))
} }
for _, entity := range schema.Types { for _, entity := range schema.Types {
tdlibType := TdlibType(entity.Name, schema) tdlibType := TdlibType(entity.Name, schema)
if tdlibType.IsInternal() || tdlibType.HasClass() { if tdlibType.IsInternal() || tdlibType.HasClass() {
continue continue
} }
buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibType.ToClassConst(), entity.Class)) buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibType.ToClassConst(), entity.Class))
} }
buf.WriteString(")") buf.WriteString(")")
buf.WriteString("\n\n") buf.WriteString("\n\n")
buf.WriteString("const (\n") buf.WriteString("const (\n")
for _, entity := range schema.Types { for _, entity := range schema.Types {
tdlibType := TdlibType(entity.Name, schema) tdlibType := TdlibType(entity.Name, schema)
if tdlibType.IsInternal() { if tdlibType.IsInternal() {
continue continue
} }
buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibType.ToTypeConst(), entity.Name)) buf.WriteString(fmt.Sprintf(" %s = %q\n", tdlibType.ToTypeConst(), entity.Name))
} }
buf.WriteString(")") buf.WriteString(")")
buf.WriteString("\n\n") buf.WriteString("\n\n")
for _, class := range schema.Classes { for _, class := range schema.Classes {
tdlibClass := TdlibClass(class.Name, schema) tdlibClass := TdlibClass(class.Name, schema)
buf.WriteString(fmt.Sprintf(`// %s buf.WriteString(fmt.Sprintf(`// %s
type %s interface { type %s interface {
%sType() string %sType() string
} }
`, class.Description, tdlibClass.ToGoType(), tdlibClass.ToGoType())) `, class.Description, tdlibClass.ToGoType(), tdlibClass.ToGoType()))
} }
for _, typ := range schema.Types { for _, typ := range schema.Types {
tdlibType := TdlibType(typ.Name, schema) tdlibType := TdlibType(typ.Name, schema)
if tdlibType.IsInternal() { if tdlibType.IsInternal() {
continue continue
} }
buf.WriteString("// " + typ.Description + "\n") buf.WriteString("// " + typ.Description + "\n")
if len(typ.Properties) > 0 { if len(typ.Properties) > 0 {
buf.WriteString(`type ` + tdlibType.ToGoType() + ` struct { buf.WriteString(`type ` + tdlibType.ToGoType() + ` struct {
meta meta
`) `)
for _, property := range typ.Properties { for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema) tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
buf.WriteString(fmt.Sprintf(" // %s\n", property.Description)) buf.WriteString(fmt.Sprintf(" // %s\n", property.Description))
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name)) buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name))
} }
buf.WriteString("}\n\n") buf.WriteString("}\n\n")
} else { } else {
buf.WriteString(`type ` + tdlibType.ToGoType() + ` struct{ buf.WriteString(`type ` + tdlibType.ToGoType() + ` struct{
meta meta
} }
`) `)
} }
buf.WriteString(fmt.Sprintf(`func (entity *%s) MarshalJSON() ([]byte, error) { buf.WriteString(fmt.Sprintf(`func (entity *%s) MarshalJSON() ([]byte, error) {
entity.meta.Type = entity.GetType() entity.meta.Type = entity.GetType()
type stub %s type stub %s
@ -95,7 +95,7 @@ type %s interface {
`, tdlibType.ToGoType(), tdlibType.ToGoType())) `, tdlibType.ToGoType(), tdlibType.ToGoType()))
buf.WriteString(fmt.Sprintf(`func (*%s) GetClass() string { buf.WriteString(fmt.Sprintf(`func (*%s) GetClass() string {
return %s return %s
} }
@ -105,35 +105,35 @@ func (*%s) GetType() string {
`, tdlibType.ToGoType(), tdlibType.ToClassConst(), tdlibType.ToGoType(), tdlibType.ToTypeConst())) `, tdlibType.ToGoType(), tdlibType.ToClassConst(), tdlibType.ToGoType(), tdlibType.ToTypeConst()))
if tdlibType.HasClass() { if tdlibType.HasClass() {
tdlibClass := TdlibClass(tdlibType.GetClass().Name, schema) tdlibClass := TdlibClass(tdlibType.GetClass().Name, schema)
buf.WriteString(fmt.Sprintf(`func (*%s) %sType() string { buf.WriteString(fmt.Sprintf(`func (*%s) %sType() string {
return %s return %s
} }
`, tdlibType.ToGoType(), tdlibClass.ToGoType(), tdlibType.ToTypeConst())) `, tdlibType.ToGoType(), tdlibClass.ToGoType(), tdlibType.ToTypeConst()))
} }
if tdlibType.HasClassProperties() { if tdlibType.HasClassProperties() {
buf.WriteString(fmt.Sprintf(`func (%s *%s) UnmarshalJSON(data []byte) error { buf.WriteString(fmt.Sprintf(`func (%s *%s) UnmarshalJSON(data []byte) error {
var tmp struct { var tmp struct {
`, typ.Name, tdlibType.ToGoType())) `, typ.Name, tdlibType.ToGoType()))
var countSimpleProperties int var countSimpleProperties int
for _, property := range typ.Properties { for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema) tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
if !tdlibTypeProperty.IsClass() || tdlibTypeProperty.IsList() { if !tdlibTypeProperty.IsClass() || tdlibTypeProperty.IsList() {
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name)) buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), property.Name))
countSimpleProperties++ countSimpleProperties++
} else { } else {
buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), "json.RawMessage", property.Name)) buf.WriteString(fmt.Sprintf(" %s %s `json:\"%s\"`\n", tdlibTypeProperty.ToGoName(), "json.RawMessage", property.Name))
} }
} }
buf.WriteString(` } buf.WriteString(` }
err := json.Unmarshal(data, &tmp) err := json.Unmarshal(data, &tmp)
if err != nil { if err != nil {
@ -142,35 +142,35 @@ func (*%s) GetType() string {
`) `)
for _, property := range typ.Properties { for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema) tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
if !tdlibTypeProperty.IsClass() || tdlibTypeProperty.IsList() { if !tdlibTypeProperty.IsClass() || tdlibTypeProperty.IsList() {
buf.WriteString(fmt.Sprintf(" %s.%s = tmp.%s\n", typ.Name, tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoName())) buf.WriteString(fmt.Sprintf(" %s.%s = tmp.%s\n", typ.Name, tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoName()))
} }
} }
if countSimpleProperties > 0 { if countSimpleProperties > 0 {
buf.WriteString("\n") buf.WriteString("\n")
} }
for _, property := range typ.Properties { for _, property := range typ.Properties {
tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema) tdlibTypeProperty := TdlibTypeProperty(property.Name, property.Type, schema)
if tdlibTypeProperty.IsClass() && !tdlibTypeProperty.IsList() { if tdlibTypeProperty.IsClass() && !tdlibTypeProperty.IsList() {
buf.WriteString(fmt.Sprintf(` field%s, _ := Unmarshal%s(tmp.%s) buf.WriteString(fmt.Sprintf(` field%s, _ := Unmarshal%s(tmp.%s)
%s.%s = field%s %s.%s = field%s
`, tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), tdlibTypeProperty.ToGoName(), typ.Name, tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoName())) `, tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoType(), tdlibTypeProperty.ToGoName(), typ.Name, tdlibTypeProperty.ToGoName(), tdlibTypeProperty.ToGoName()))
} }
} }
buf.WriteString(` return nil buf.WriteString(` return nil
} }
`) `)
} }
} }
return buf.Bytes() return buf.Bytes()
} }

View file

@ -1,27 +1,27 @@
package codegen package codegen
import ( import (
"github.com/zelenin/go-tdlib/tlparser" "bytes"
"fmt" "fmt"
"bytes" "github.com/zelenin/go-tdlib/tlparser"
) )
func GenerateUnmarshalers(schema *tlparser.Schema, packageName string) []byte { func GenerateUnmarshalers(schema *tlparser.Schema, packageName string) []byte {
buf := bytes.NewBufferString("") buf := bytes.NewBufferString("")
buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName)) buf.WriteString(fmt.Sprintf("%s\n\npackage %s\n\n", header, packageName))
buf.WriteString(`import ( buf.WriteString(`import (
"encoding/json" "encoding/json"
"fmt" "fmt"
) )
`) `)
for _, class := range schema.Classes { for _, class := range schema.Classes {
tdlibClass := TdlibClass(class.Name, schema) tdlibClass := TdlibClass(class.Name, schema)
buf.WriteString(fmt.Sprintf(`func Unmarshal%s(data json.RawMessage) (%s, error) { buf.WriteString(fmt.Sprintf(`func Unmarshal%s(data json.RawMessage) (%s, error) {
var meta meta var meta meta
err := json.Unmarshal(data, &meta) err := json.Unmarshal(data, &meta)
@ -32,30 +32,30 @@ func GenerateUnmarshalers(schema *tlparser.Schema, packageName string) []byte {
switch meta.Type { switch meta.Type {
`, tdlibClass.ToGoType(), tdlibClass.ToGoType())) `, tdlibClass.ToGoType(), tdlibClass.ToGoType()))
for _, subType := range tdlibClass.GetSubTypes() { for _, subType := range tdlibClass.GetSubTypes() {
buf.WriteString(fmt.Sprintf(` case %s: buf.WriteString(fmt.Sprintf(` case %s:
return Unmarshal%s(data) return Unmarshal%s(data)
`, subType.ToTypeConst(), subType.ToGoType())) `, subType.ToTypeConst(), subType.ToGoType()))
} }
buf.WriteString(` default: buf.WriteString(` default:
return nil, fmt.Errorf("Error unmarshaling. Unknown type: " + meta.Type) return nil, fmt.Errorf("Error unmarshaling. Unknown type: " + meta.Type)
} }
} }
`) `)
} }
for _, typ := range schema.Types { for _, typ := range schema.Types {
tdlibType := TdlibType(typ.Name, schema) tdlibType := TdlibType(typ.Name, schema)
if tdlibType.IsList() || tdlibType.IsInternal() { if tdlibType.IsList() || tdlibType.IsInternal() {
continue continue
} }
buf.WriteString(fmt.Sprintf(`func Unmarshal%s(data json.RawMessage) (*%s, error) { buf.WriteString(fmt.Sprintf(`func Unmarshal%s(data json.RawMessage) (*%s, error) {
var resp %s var resp %s
err := json.Unmarshal(data, &resp) err := json.Unmarshal(data, &resp)
@ -65,9 +65,9 @@ func GenerateUnmarshalers(schema *tlparser.Schema, packageName string) []byte {
`, tdlibType.ToGoType(), tdlibType.ToGoType(), tdlibType.ToGoType())) `, tdlibType.ToGoType(), tdlibType.ToGoType(), tdlibType.ToGoType()))
} }
buf.WriteString(`func UnmarshalType(data json.RawMessage) (Type, error) { buf.WriteString(`func UnmarshalType(data json.RawMessage) (Type, error) {
var meta meta var meta meta
err := json.Unmarshal(data, &meta) err := json.Unmarshal(data, &meta)
@ -78,25 +78,25 @@ func GenerateUnmarshalers(schema *tlparser.Schema, packageName string) []byte {
switch meta.Type { switch meta.Type {
`) `)
for _, typ := range schema.Types { for _, typ := range schema.Types {
tdlibType := TdlibType(typ.Name, schema) tdlibType := TdlibType(typ.Name, schema)
if tdlibType.IsList() || tdlibType.IsInternal() { if tdlibType.IsList() || tdlibType.IsInternal() {
continue continue
} }
buf.WriteString(fmt.Sprintf(` case %s: buf.WriteString(fmt.Sprintf(` case %s:
return Unmarshal%s(data) return Unmarshal%s(data)
`, tdlibType.ToTypeConst(), tdlibType.ToGoType())) `, tdlibType.ToTypeConst(), tdlibType.ToGoType()))
} }
buf.WriteString(` default: buf.WriteString(` default:
return nil, fmt.Errorf("Error unmarshaling. Unknown type: " + meta.Type) return nil, fmt.Errorf("Error unmarshaling. Unknown type: " + meta.Type)
} }
} }
`) `)
return buf.Bytes() return buf.Bytes()
} }

View file

@ -1,74 +1,74 @@
package tlparser package tlparser
import ( import (
"bufio" "bufio"
"fmt" "fmt"
"io" "io"
"strings" "strings"
) )
func ParseCode(reader io.Reader, schema *Schema) error { func ParseCode(reader io.Reader, schema *Schema) error {
var prevLine string var prevLine string
var curLine string var curLine string
userMethods := map[string]bool{} userMethods := map[string]bool{}
botMethods := map[string]bool{} botMethods := map[string]bool{}
scanner := bufio.NewScanner(reader) scanner := bufio.NewScanner(reader)
for scanner.Scan() { for scanner.Scan() {
prevLine = curLine prevLine = curLine
curLine = scanner.Text() curLine = scanner.Text()
if strings.Contains(curLine, "CHECK_IS_USER();") { if strings.Contains(curLine, "CHECK_IS_USER();") {
fields := strings.Fields(prevLine) fields := strings.Fields(prevLine)
for _, field := range fields { for _, field := range fields {
var methodName string var methodName string
n, err := fmt.Sscanf(field, "td_api::%s", &methodName) n, err := fmt.Sscanf(field, "td_api::%s", &methodName)
if err == nil && n > 0 { if err == nil && n > 0 {
userMethods[methodName] = true userMethods[methodName] = true
} }
} }
} }
if strings.Contains(curLine, "CHECK_IS_BOT();") { if strings.Contains(curLine, "CHECK_IS_BOT();") {
fields := strings.Fields(prevLine) fields := strings.Fields(prevLine)
for _, field := range fields { for _, field := range fields {
var methodName string var methodName string
n, err := fmt.Sscanf(field, "td_api::%s", &methodName) n, err := fmt.Sscanf(field, "td_api::%s", &methodName)
if err == nil && n > 0 { if err == nil && n > 0 {
botMethods[methodName] = true botMethods[methodName] = true
} }
} }
} }
} }
err := scanner.Err() err := scanner.Err()
if err != nil { if err != nil {
return err return err
} }
var ok bool var ok bool
for index, _ := range schema.Functions { for index, _ := range schema.Functions {
hasType := false hasType := false
_, ok = userMethods[schema.Functions[index].Name] _, ok = userMethods[schema.Functions[index].Name]
if ok { if ok {
schema.Functions[index].Type = FUNCTION_TYPE_USER schema.Functions[index].Type = FUNCTION_TYPE_USER
hasType = true hasType = true
} }
_, ok = botMethods[schema.Functions[index].Name] _, ok = botMethods[schema.Functions[index].Name]
if ok { if ok {
schema.Functions[index].Type = FUNCTION_TYPE_BOT schema.Functions[index].Type = FUNCTION_TYPE_BOT
hasType = true hasType = true
} }
if !hasType { if !hasType {
schema.Functions[index].Type = FUNCTION_TYPE_COMMON schema.Functions[index].Type = FUNCTION_TYPE_COMMON
} }
ok = false ok = false
} }
return nil return nil
} }

View file

@ -1,174 +1,174 @@
package tlparser package tlparser
import ( import (
"io" "bufio"
"strings" "io"
"bufio" "strings"
) )
func Parse(reader io.Reader) (*Schema, error) { func Parse(reader io.Reader) (*Schema, error) {
schema := &Schema{ schema := &Schema{
Types: []*Type{}, Types: []*Type{},
Classes: []*Class{}, Classes: []*Class{},
Functions: []*Function{}, Functions: []*Function{},
} }
scanner := bufio.NewScanner(reader) scanner := bufio.NewScanner(reader)
hitFunctions := false hitFunctions := false
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
switch { switch {
case strings.HasPrefix(line, "//@description"): case strings.HasPrefix(line, "//@description"):
if hitFunctions { if hitFunctions {
schema.Functions = append(schema.Functions, parseFunction(line, scanner)) schema.Functions = append(schema.Functions, parseFunction(line, scanner))
} else { } else {
schema.Types = append(schema.Types, parseType(line, scanner)) schema.Types = append(schema.Types, parseType(line, scanner))
} }
case strings.HasPrefix(line, "//@class"): case strings.HasPrefix(line, "//@class"):
schema.Classes = append(schema.Classes, parseClass(line, scanner)) schema.Classes = append(schema.Classes, parseClass(line, scanner))
case strings.Contains(line, "---functions---"): case strings.Contains(line, "---functions---"):
hitFunctions = true hitFunctions = true
case line == "": case line == "":
default: default:
bodyFields := strings.Fields(line) bodyFields := strings.Fields(line)
name := bodyFields[0] name := bodyFields[0]
class := strings.TrimRight(bodyFields[len(bodyFields)-1], ";") class := strings.TrimRight(bodyFields[len(bodyFields)-1], ";")
if hitFunctions { if hitFunctions {
schema.Functions = append(schema.Functions, &Function{ schema.Functions = append(schema.Functions, &Function{
Name: name, Name: name,
Description: "", Description: "",
Class: class, Class: class,
Properties: []*Property{}, Properties: []*Property{},
IsSynchronous: false, IsSynchronous: false,
Type: FUNCTION_TYPE_UNKNOWN, Type: FUNCTION_TYPE_UNKNOWN,
}) })
} else { } else {
if name == "vector" { if name == "vector" {
name = "vector<t>" name = "vector<t>"
class = "Vector<T>" class = "Vector<T>"
} }
schema.Types = append(schema.Types, &Type{ schema.Types = append(schema.Types, &Type{
Name: name, Name: name,
Description: "", Description: "",
Class: class, Class: class,
Properties: []*Property{}, Properties: []*Property{},
}) })
} }
} }
} }
return schema, nil return schema, nil
} }
func parseType(firstLine string, scanner *bufio.Scanner) *Type { func parseType(firstLine string, scanner *bufio.Scanner) *Type {
name, description, class, properties, _ := parseEntity(firstLine, scanner) name, description, class, properties, _ := parseEntity(firstLine, scanner)
return &Type{ return &Type{
Name: name, Name: name,
Description: description, Description: description,
Class: class, Class: class,
Properties: properties, Properties: properties,
} }
} }
func parseFunction(firstLine string, scanner *bufio.Scanner) *Function { func parseFunction(firstLine string, scanner *bufio.Scanner) *Function {
name, description, class, properties, isSynchronous := parseEntity(firstLine, scanner) name, description, class, properties, isSynchronous := parseEntity(firstLine, scanner)
return &Function{ return &Function{
Name: name, Name: name,
Description: description, Description: description,
Class: class, Class: class,
Properties: properties, Properties: properties,
IsSynchronous: isSynchronous, IsSynchronous: isSynchronous,
Type: FUNCTION_TYPE_UNKNOWN, Type: FUNCTION_TYPE_UNKNOWN,
} }
} }
func parseClass(firstLine string, scanner *bufio.Scanner) *Class { func parseClass(firstLine string, scanner *bufio.Scanner) *Class {
class := &Class{ class := &Class{
Name: "", Name: "",
Description: "", Description: "",
} }
classLineParts := strings.Split(firstLine, "@") classLineParts := strings.Split(firstLine, "@")
_, class.Name = parseProperty(classLineParts[1]) _, class.Name = parseProperty(classLineParts[1])
_, class.Description = parseProperty(classLineParts[2]) _, class.Description = parseProperty(classLineParts[2])
return class return class
} }
func parseEntity(firstLine string, scanner *bufio.Scanner) (string, string, string, []*Property, bool) { func parseEntity(firstLine string, scanner *bufio.Scanner) (string, string, string, []*Property, bool) {
name := "" name := ""
description := "" description := ""
class := "" class := ""
properties := []*Property{} properties := []*Property{}
propertiesLine := strings.TrimLeft(firstLine, "//") propertiesLine := strings.TrimLeft(firstLine, "//")
Loop: Loop:
for scanner.Scan() { for scanner.Scan() {
line := scanner.Text() line := scanner.Text()
switch { switch {
case strings.HasPrefix(line, "//@"): case strings.HasPrefix(line, "//@"):
propertiesLine += " " + strings.TrimLeft(line, "//") propertiesLine += " " + strings.TrimLeft(line, "//")
case strings.HasPrefix(line, "//-"): case strings.HasPrefix(line, "//-"):
propertiesLine += " " + strings.TrimLeft(line, "//-") propertiesLine += " " + strings.TrimLeft(line, "//-")
default: default:
bodyFields := strings.Fields(line) bodyFields := strings.Fields(line)
name = bodyFields[0] name = bodyFields[0]
for _, rawProperty := range bodyFields[1 : len(bodyFields)-2] { for _, rawProperty := range bodyFields[1 : len(bodyFields)-2] {
propertyParts := strings.Split(rawProperty, ":") propertyParts := strings.Split(rawProperty, ":")
property := &Property{ property := &Property{
Name: propertyParts[0], Name: propertyParts[0],
Type: propertyParts[1], Type: propertyParts[1],
} }
properties = append(properties, property) properties = append(properties, property)
} }
class = strings.TrimRight(bodyFields[len(bodyFields)-1], ";") class = strings.TrimRight(bodyFields[len(bodyFields)-1], ";")
break Loop break Loop
} }
} }
rawProperties := strings.Split(propertiesLine, "@") rawProperties := strings.Split(propertiesLine, "@")
for _, rawProperty := range rawProperties[1:] { for _, rawProperty := range rawProperties[1:] {
name, value := parseProperty(rawProperty) name, value := parseProperty(rawProperty)
switch { switch {
case name == "description": case name == "description":
description = value description = value
default: default:
name = strings.TrimPrefix(name, "param_") name = strings.TrimPrefix(name, "param_")
property := getProperty(properties, name) property := getProperty(properties, name)
property.Description = value property.Description = value
} }
} }
return name, description, class, properties, strings.Contains(description, "Can be called synchronously") return name, description, class, properties, strings.Contains(description, "Can be called synchronously")
} }
func parseProperty(str string) (string, string) { func parseProperty(str string) (string, string) {
strParts := strings.Fields(str) strParts := strings.Fields(str)
return strParts[0], strings.Join(strParts[1:], " ") return strParts[0], strings.Join(strParts[1:], " ")
} }
func getProperty(properties []*Property, name string) *Property { func getProperty(properties []*Property, name string) *Property {
for _, property := range properties { for _, property := range properties {
if property.Name == name { if property.Name == name {
return property return property
} }
} }
return nil return nil
} }

View file

@ -1,43 +1,43 @@
package tlparser package tlparser
type Schema struct { type Schema struct {
Types []*Type `json:"types"` Types []*Type `json:"types"`
Classes []*Class `json:"classes"` Classes []*Class `json:"classes"`
Functions []*Function `json:"functions"` Functions []*Function `json:"functions"`
} }
type Type struct { type Type struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
Class string `json:"class"` Class string `json:"class"`
Properties []*Property `json:"properties"` Properties []*Property `json:"properties"`
} }
type Class struct { type Class struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
} }
type FunctionType int type FunctionType int
const ( const (
FUNCTION_TYPE_UNKNOWN FunctionType = iota FUNCTION_TYPE_UNKNOWN FunctionType = iota
FUNCTION_TYPE_COMMON FUNCTION_TYPE_COMMON
FUNCTION_TYPE_USER FUNCTION_TYPE_USER
FUNCTION_TYPE_BOT FUNCTION_TYPE_BOT
) )
type Function struct { type Function struct {
Name string `json:"name"` Name string `json:"name"`
Description string `json:"description"` Description string `json:"description"`
Class string `json:"class"` Class string `json:"class"`
Properties []*Property `json:"properties"` Properties []*Property `json:"properties"`
IsSynchronous bool `json:"is_synchronous"` IsSynchronous bool `json:"is_synchronous"`
Type FunctionType `json:"type"` Type FunctionType `json:"type"`
} }
type Property struct { type Property struct {
Name string `json:"name"` Name string `json:"name"`
Type string `json:"type"` Type string `json:"type"`
Description string `json:"description"` Description string `json:"description"`
} }