github.com/machinefi/w3bstream@v1.6.5-rc9.0.20240426031326-b8c7c4876e72/pkg/depends/kit/statusxgen/generator.go (about) 1 package statusxgen 2 3 import ( 4 "go/types" 5 "log" 6 "path" 7 "path/filepath" 8 "runtime" 9 10 gen "github.com/machinefi/w3bstream/pkg/depends/gen/codegen" 11 "github.com/machinefi/w3bstream/pkg/depends/kit/statusx" 12 "github.com/machinefi/w3bstream/pkg/depends/x/misc/must" 13 "github.com/machinefi/w3bstream/pkg/depends/x/pkgx" 14 "github.com/machinefi/w3bstream/pkg/depends/x/stringsx" 15 ) 16 17 func New(pkg *pkgx.Pkg) *Generator { 18 return &Generator{ 19 pkg: pkg, 20 scanner: NewScanner(pkg), 21 errs: map[string]*StatusError{}, 22 } 23 } 24 25 type Generator struct { 26 pkg *pkgx.Pkg 27 scanner *Scanner 28 errs map[string]*StatusError 29 } 30 31 func (g *Generator) Scan(names ...string) { 32 for _, name := range names { 33 typeName := g.pkg.TypeName(name) 34 g.errs[name] = &StatusError{ 35 TypeName: typeName, 36 Errors: g.scanner.StatusError(typeName), 37 } 38 } 39 } 40 41 func (g *Generator) Output(cwd string) { 42 for _, e := range g.errs { 43 dir, _ := filepath.Rel( 44 cwd, 45 must.String(pkgx.PkgPathByPath(e.TypeName.Pkg().Path())), 46 ) 47 filename := gen.GenerateFileSuffix(path.Join(dir, stringsx.LowerSnakeCase(e.Name())+".go")) 48 49 f := gen.NewFile(e.TypeName.Pkg().Name(), filename) 50 51 if err := e.WriteToFile(f); err != nil { 52 log.Printf("%s generate failed: %v", filename, err) 53 } 54 } 55 } 56 57 type StatusError struct { 58 TypeName *types.TypeName 59 Errors []*statusx.StatusErr 60 } 61 62 func (s *StatusError) Name() string { return s.TypeName.Name() } 63 64 func (s *StatusError) SnippetTypeAssert(f *gen.File) gen.Snippet { 65 return gen.Exprer( 66 "var _ ? = (*?)(nil)", 67 gen.Type(f.Use(PkgPath, "Error")), 68 gen.Type(s.Name()), 69 ) 70 } 71 72 func (s *StatusError) SnippetStatusErr(f *gen.File) gen.Snippet { 73 t := gen.Type(f.Use(PkgPath, "StatusErr")) 74 75 return gen.Func().Named("StatusErr").MethodOf(gen.Var(gen.Type(s.Name()), "v")). 76 Return(gen.Var(gen.Star(t))). 77 Do( 78 f.Expr(`return &?{ 79 Key: v.Key(), 80 Code: v.Code(), 81 Msg: v.Msg(), 82 CanBeTalk: v.CanBeTalk(), 83 }`, 84 t), 85 ) 86 } 87 88 func (s *StatusError) SnippetUnwrap(f *gen.File) gen.Snippet { 89 return gen.Func().Named("Unwrap").MethodOf(gen.Var(gen.Type(s.Name()), "v")). 90 Return(gen.Var(gen.Error)). 91 Do(f.Expr(`return v.StatusErr()`)) 92 } 93 94 func (s *StatusError) SnippetError(f *gen.File) gen.Snippet { 95 return gen.Func().Named("Error").MethodOf(gen.Var(gen.Type(s.Name()), "v")). 96 Return(gen.Var(gen.String)). 97 Do(f.Expr(`return v.StatusErr().Error()`)) 98 } 99 100 func (s *StatusError) SnippetStatusCode(f *gen.File) gen.Snippet { 101 return gen.Func().Named("StatusCode").MethodOf(gen.Var(gen.Type(s.Name()), "v")). 102 Return(gen.Var(gen.Int)). 103 Do( 104 f.Expr( 105 `return ?(int(v))`, 106 gen.Ident(f.Use(PkgPath, "StatusCodeFromCode")), 107 ), 108 ) 109 } 110 111 func (s *StatusError) SnippetCode(f *gen.File) gen.Snippet { 112 return gen.Func().Named("Code").MethodOf(gen.Var(gen.Type(s.Name()), "v")). 113 Return(gen.Var(gen.Int)). 114 Do( 115 f.Expr(`if with, ok := (interface{})(v).(?); ok { 116 return with.ServiceCode() + int(v) 117 } 118 return int(v)`, 119 gen.Ident(f.Use(PkgPath, "ServiceCode"))), 120 ) 121 } 122 123 func (s *StatusError) SnippetKey(f *gen.File) gen.Snippet { 124 clauses := make([]*gen.SnippetCaseClause, 0) 125 126 for _, e := range s.Errors { 127 clauses = append(clauses, 128 gen.CaseClause(gen.Ident(e.Key)).Do(gen.Return(f.Value(e.Key))), 129 ) 130 } 131 132 return gen.Func().Named("Key").MethodOf(gen.Var(gen.Type(s.Name()), "v")). 133 Return(gen.Var(gen.String)). 134 Do( 135 gen.Switch(gen.Ident("v")). 136 When( 137 clauses..., 138 ), 139 gen.Return(f.Value("UNKNOWN")), 140 ) 141 } 142 143 func (s *StatusError) SnippetMsg(f *gen.File) gen.Snippet { 144 clauses := make([]*gen.SnippetCaseClause, 0) 145 146 for _, e := range s.Errors { 147 clauses = append(clauses, 148 gen.CaseClause(gen.Ident(e.Key)).Do(gen.Return(f.Value(e.Msg)))) 149 } 150 151 return gen.Func().Named("Msg").MethodOf(gen.Var(gen.Type(s.Name()), "v")). 152 Return(gen.Var(gen.String)). 153 Do( 154 gen.Switch(gen.Ident("v")). 155 When( 156 clauses..., 157 ), 158 gen.Return(f.Value("-")), 159 ) 160 } 161 162 func (s *StatusError) SnippetCanBeTalk(f *gen.File) gen.Snippet { 163 clauses := make([]*gen.SnippetCaseClause, 0) 164 165 for _, e := range s.Errors { 166 clauses = append(clauses, 167 gen.CaseClause(gen.Ident(e.Key)).Do(gen.Return(f.Value(e.CanBeTalk))), 168 ) 169 } 170 171 return gen.Func().Named("CanBeTalk").MethodOf(gen.Var(gen.Type(s.Name()), "v")). 172 Return(gen.Var(gen.Bool)).Do( 173 gen.Switch(gen.Ident("v")).When( 174 clauses..., 175 ), 176 gen.Return(f.Value(false)), 177 ) 178 } 179 180 func (s *StatusError) WriteToFile(f *gen.File) error { 181 f.WriteSnippet( 182 s.SnippetTypeAssert(f), 183 s.SnippetStatusErr(f), 184 s.SnippetUnwrap(f), 185 s.SnippetError(f), 186 s.SnippetStatusCode(f), 187 s.SnippetCode(f), 188 s.SnippetKey(f), 189 s.SnippetMsg(f), 190 s.SnippetCanBeTalk(f), 191 ) 192 _, err := f.Write() 193 return err 194 } 195 196 var PkgPath string 197 198 func init() { 199 _, current, _, _ := runtime.Caller(0) 200 dir := filepath.Join(filepath.Dir(current), "../statusx") 201 PkgPath = must.String(pkgx.PkgIdByPath(dir)) 202 }