tons of code

This commit is contained in:
Egor Aristov 2025-10-21 18:46:52 +03:00
parent 6c396107c8
commit 12e472c8e5
Signed by: egor3f
GPG Key ID: 40482A264AAEC85F
6 changed files with 135 additions and 63 deletions

View File

@ -0,0 +1,17 @@
// Code generated by kitcom. DO NOT EDIT.
package main
import kittenipc "efprojects.com/kitten-ipc"
type TsIpcApi struct {
Ipc *kittenipc.KittenIPC
}
func (t *TsIpcApi) Div(
a int, b int,
) int {
return t.Ipc.Call(
"Div", a, b,
)
}

View File

@ -1,7 +1,7 @@
/** /**
* @kittenipc api * @kittenipc api
*/ */
class IpcApi { class TsIpcApi {
Div(a: number, b: number): number { Div(a: number, b: number): number {
return a / b; return a / b;
} }

28
kitcom/go_gen.tmpl Normal file
View File

@ -0,0 +1,28 @@
{{- /*gotype: efprojects.com/kitten-ipc/kitcom.genData*/ -}}
// Code generated by kitcom. DO NOT EDIT.
package {{.PkgName}}
import kittenipc "efprojects.com/kitten-ipc"
{{range $e := .Api.Endpoints}}
type {{.Name}} struct {
Ipc *kittenipc.KittenIPC
}
{{range $mtd := .Methods}}
func ({{$e.Name | receiver}} *{{$e.Name}}) {{$mtd.Name}} (
{{range $mtd.Params}}{{.Name}} {{.Type | typedef}}, {{end}}
) (
{{range $mtd.Ret}}{{.Type | typedef}}, {{end}}
) {
return {{$e.Name | receiver}}.Ipc.Call(
"{{$mtd.Name}}", {{range $mtd.Pars}}{{.Name}}, {{end}}
)
}
{{end}}
{{end}}

View File

@ -1,49 +1,75 @@
package main package main
import ( import (
"errors" "bytes"
"fmt" "fmt"
"html/template" "go/format"
"os" "os"
"path/filepath"
"strings" "strings"
"text/template"
) )
type GoApiGenerator struct { type genData struct {
PkgName string
Api *Api
} }
var tpl = template.Must(template.New("gotpl").Parse(strings.TrimSpace(` type GoApiGenerator struct {
pkgName string
}
`)))
func (g *GoApiGenerator) Generate(api *Api, destFile string) error { func (g *GoApiGenerator) Generate(api *Api, destFile string) error {
destFileBak := filepath.Join(destFile, ".bak") tplCtx := genData{
_, err := os.Stat(destFile) PkgName: g.pkgName,
if err != nil && !errors.Is(err, os.ErrNotExist) { Api: api,
return fmt.Errorf("stat destination file: %w", err)
}
if !errors.Is(err, os.ErrNotExist) {
if err := os.Rename(destFile, destFileBak); err != nil {
return fmt.Errorf("backup destination file: %w", err)
}
} }
tpl := template.New("gogen")
tpl = tpl.Funcs(map[string]any{
"receiver": func(name string) string {
return strings.ToLower(name)[0:1]
},
"typedef": func(t ValType) (string, error) {
td, ok := map[ValType]string{
TInt: "int",
TString: "string",
TBool: "bool",
}[t]
if !ok {
return "", fmt.Errorf("cannot generate type %v", t)
}
return td, nil
},
})
tpl = template.Must(tpl.ParseFiles("./go_gen.tmpl"))
var buf bytes.Buffer
if err := tpl.ExecuteTemplate(&buf, "go_gen.tmpl", tplCtx); err != nil {
return fmt.Errorf("execute template: %w", err)
}
if err := g.writeDest(destFile, buf.Bytes()); err != nil {
return fmt.Errorf("write file: %w", err)
}
return nil
}
func (g *GoApiGenerator) writeDest(destFile string, bytes []byte) error {
f, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, 0644) f, err := os.OpenFile(destFile, os.O_WRONLY|os.O_CREATE, 0644)
if err != nil { if err != nil {
return fmt.Errorf("open destination file: %w", err) return fmt.Errorf("open destination file: %w", err)
} }
defer f.Close() defer f.Close()
if err := tpl.Execute(f, api); err != nil { formatted, err := format.Source(bytes)
return fmt.Errorf("execute template: %w", err) if err != nil {
return fmt.Errorf("format source: %w", err)
} }
if _, err := os.Stat(destFileBak); err == nil { if _, err := f.Write(formatted); err != nil {
if err := os.Remove(destFileBak); err != nil { return fmt.Errorf("write formatted source: %w", err)
return fmt.Errorf("remove backup file: %w", err)
}
} }
return nil return nil
} }

View File

@ -3,23 +3,13 @@ package main
import ( import (
"flag" "flag"
"fmt" "fmt"
"go/token"
"log" "log"
"os" "os"
"path" "path"
"path/filepath" "path/filepath"
) )
var (
Src string
Dest string
)
func parseFlags() {
flag.StringVar(&Src, "src", "", "Source file")
flag.StringVar(&Dest, "dest", "", "Dest file")
flag.Parse()
}
type ValType int type ValType int
// todo check TInt size < 64 // todo check TInt size < 64
@ -41,14 +31,19 @@ type Val struct {
type Method struct { type Method struct {
Name string Name string
Pars []Val Params []Val
Ret []Val Ret []Val
} }
type Api struct { type Endpoint struct {
Name string
Methods []Method Methods []Method
} }
type Api struct {
Endpoints []Endpoint
}
type ApiParser interface { type ApiParser interface {
Parse(sourceFile string) (*Api, error) Parse(sourceFile string) (*Api, error)
} }
@ -64,17 +59,21 @@ func main() {
// log.Panic("GOFILE must be set") // log.Panic("GOFILE must be set")
//} //}
parseFlags() src := flag.String("src", "", "Source file")
if Src == "" || Dest == "" { dest := flag.String("dest", "", "Dest file")
pkgName := flag.String("pkgname", "", "Package name (for go)")
flag.Parse()
if *src == "" || *dest == "" {
log.Panic("source and destination must be set") log.Panic("source and destination must be set")
} }
srcAbs, err := filepath.Abs(Src) srcAbs, err := filepath.Abs(*src)
if err != nil { if err != nil {
log.Panic(err) log.Panic(err)
} }
destAbs, err := filepath.Abs(Dest) destAbs, err := filepath.Abs(*dest)
if err != nil { if err != nil {
log.Panic(err) log.Panic(err)
} }
@ -93,7 +92,7 @@ func main() {
log.Panic(err) log.Panic(err)
} }
apiGenerator, err := apiGeneratorByExt(destAbs) apiGenerator, err := apiGeneratorByExt(destAbs, *pkgName)
if err != nil { if err != nil {
log.Panic(err) log.Panic(err)
} }
@ -129,10 +128,18 @@ func apiParserByExt(src string) (ApiParser, error) {
} }
} }
func apiGeneratorByExt(dest string) (ApiGenerator, error) { func apiGeneratorByExt(dest string, pkgName string) (ApiGenerator, error) {
switch path.Ext(dest) { switch path.Ext(dest) {
case ".go": case ".go":
return &GoApiGenerator{}, nil if pkgName == "" {
return nil, fmt.Errorf("package name must be set for Go generation")
}
if !token.IsIdentifier(pkgName) {
return nil, fmt.Errorf("invalid package name: %s", pkgName)
}
return &GoApiGenerator{
pkgName: pkgName,
}, nil
case ".ts": case ".ts":
return &TypescriptApiGenerator{}, nil return &TypescriptApiGenerator{}, nil
case ".js": case ".js":

View File

@ -18,10 +18,6 @@ const TagComment = "api"
type TypescriptApiParser struct { type TypescriptApiParser struct {
} }
type apiClass struct {
methods []Method
}
func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) { func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
f, err := os.Open(sourceFilePath) f, err := os.Open(sourceFilePath)
@ -44,7 +40,7 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
}, string(fileContents), core.ScriptKindTS) }, string(fileContents), core.ScriptKindTS)
_ = sourceFile _ = sourceFile
var apiClasses []apiClass var api Api
sourceFile.ForEachChild(func(node *ast.Node) bool { sourceFile.ForEachChild(func(node *ast.Node) bool {
if node.Kind != ast.KindClassDeclaration { if node.Kind != ast.KindClassDeclaration {
@ -78,7 +74,9 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
return false return false
} }
var apiCls apiClass var endpoint Endpoint
endpoint.Name = cls.Name().Text()
for _, member := range cls.MemberList().Nodes { for _, member := range cls.MemberList().Nodes {
if member.Kind != ast.KindMethodDeclaration { if member.Kind != ast.KindMethodDeclaration {
@ -103,7 +101,7 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
err = fmt.Errorf("parameter type %s is not supported yet", par.Type.Kind) err = fmt.Errorf("parameter type %s is not supported yet", par.Type.Kind)
return false return false
} }
apiMethod.Pars = append(apiMethod.Pars, apiPar) apiMethod.Params = append(apiMethod.Params, apiPar)
} }
var apiRet Val var apiRet Val
switch method.Type.Kind { switch method.Type.Kind {
@ -118,10 +116,10 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
return false return false
} }
apiMethod.Ret = []Val{apiRet} apiMethod.Ret = []Val{apiRet}
apiCls.methods = append(apiCls.methods, apiMethod) endpoint.Methods = append(endpoint.Methods, apiMethod)
} }
apiClasses = append(apiClasses, apiCls) api.Endpoints = append(api.Endpoints, endpoint)
return false return false
}) })
@ -130,13 +128,9 @@ func (t *TypescriptApiParser) Parse(sourceFilePath string) (*Api, error) {
return nil, err return nil, err
} }
if len(apiClasses) == 0 { if len(api.Endpoints) == 0 {
return nil, fmt.Errorf("no api class found") return nil, fmt.Errorf("no api class found")
} }
if len(apiClasses) > 1 { return &api, nil
return nil, fmt.Errorf("multiple api classes found")
}
return &Api{Methods: apiClasses[0].methods}, nil
} }