/* * Copyright 2022 CloudWeGo Authors * * Licensed under the Apache License, Version 2.0 (the "License"); * you may not use this file except in compliance with the License. * You may obtain a copy of the License at * * http://www.apache.org/licenses/LICENSE-2.0 * * Unless required by applicable law or agreed to in writing, software * distributed under the License is distributed on an "AS IS" BASIS, * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. * See the License for the specific language governing permissions and * limitations under the License. */ package model import ( "errors" "fmt" "strings" ) type Kind uint const ( KindInvalid Kind = iota KindBool KindInt KindInt8 KindInt16 KindInt32 KindInt64 KindUint KindUint8 KindUint16 KindUint32 KindUint64 KindUintptr KindFloat32 KindFloat64 KindComplex64 KindComplex128 KindArray KindChan KindFunc KindInterface KindMap KindPtr KindSlice KindString KindStruct KindUnsafePointer ) type Category int64 const ( CategoryConstant Category = 1 CategoryBinary Category = 8 CategoryMap Category = 9 CategoryList Category = 10 CategorySet Category = 11 CategoryEnum Category = 12 CategoryStruct Category = 13 CategoryUnion Category = 14 CategoryException Category = 15 CategoryTypedef Category = 16 CategoryService Category = 17 ) type Model struct { FilePath string Package string Imports map[string]*Model //{{import}}:Model // rendering data PackageName string // Imports map[string]string //{{alias}}:{{import}} Typedefs []TypeDef Constants []Constant Variables []Variable Functions []Function Enums []Enum Structs []Struct Methods []Method Oneofs []Oneof } func (m Model) IsEmpty() bool { return len(m.Typedefs) == 0 && len(m.Constants) == 0 && len(m.Variables) == 0 && len(m.Functions) == 0 && len(m.Enums) == 0 && len(m.Structs) == 0 && len(m.Methods) == 0 } type Models []*Model func (a *Models) MergeMap(b map[string]*Model) { for _, v := range b { insert := true for _, p := range *a { if p == v { insert = false } } if insert { *a = append(*a, v) } } return } func (a *Models) MergeArray(b []*Model) { for _, v := range b { insert := true for _, p := range *a { if p == v { insert = false } } if insert { *a = append(*a, v) } } return } type RequiredNess int const ( RequiredNess_Default RequiredNess = 0 RequiredNess_Required RequiredNess = 1 RequiredNess_Optional RequiredNess = 2 ) type Type struct { Name string Scope *Model Kind Kind Indirect bool Category Category Extra []*Type // [{key_type},{value_type}] for map, [{element_type}] for list or set HasNew bool } func (rt *Type) ResolveDefaultValue() string { if rt == nil { return "" } switch rt.Kind { case KindInt, KindInt8, KindInt16, KindInt32, KindInt64, KindUint, KindUint16, KindUint32, KindUint64, KindFloat32, KindFloat64, KindComplex64, KindComplex128: return "0" case KindBool: return "false" case KindString: return "\"\"" default: return "nil" } } func (rt *Type) ResolveNameForTypedef(scope *Model) (string, error) { if rt == nil { return "", errors.New("type is nil") } name := rt.Name if rt.Scope == nil { return rt.Name, nil } switch rt.Kind { case KindArray, KindSlice: if len(rt.Extra) != 1 { return "", fmt.Errorf("the type: %s should have 1 extra type, but has %d", rt.Name, len(rt.Extra)) } resolveName, err := rt.Extra[0].ResolveName(scope) if err != nil { return "", err } name = fmt.Sprintf("[]%s", resolveName) case KindMap: if len(rt.Extra) != 2 { return "", fmt.Errorf("the type: %s should have 2 extra types, but has %d", rt.Name, len(rt.Extra)) } resolveKey, err := rt.Extra[0].ResolveName(scope) if err != nil { return "", err } resolveValue, err := rt.Extra[1].ResolveName(scope) if err != nil { return "", err } name = fmt.Sprintf("map[%s]%s", resolveKey, resolveValue) case KindChan: if len(rt.Extra) != 1 { return "", fmt.Errorf("the type: %s should have 1 extra type, but has %d", rt.Name, len(rt.Extra)) } resolveName, err := rt.Extra[0].ResolveName(scope) if err != nil { return "", err } name = fmt.Sprintf("chan %s", resolveName) } if scope != nil && rt.Scope != &BaseModel && rt.Scope.Package != scope.Package { name = rt.Scope.PackageName + "." + name } return name, nil } func (rt *Type) ResolveName(scope *Model) (string, error) { if rt == nil { return "", fmt.Errorf("type is nil") } name := rt.Name if rt.Scope == nil { if rt.Kind == KindStruct { return "*" + rt.Name, nil } return rt.Name, nil } if rt.Category == CategoryTypedef { if scope != nil && rt.Scope != &BaseModel && rt.Scope.Package != scope.Package { name = rt.Scope.PackageName + "." + name } if rt.Kind == KindStruct { name = "*" + name } return name, nil } switch rt.Kind { case KindArray, KindSlice: if len(rt.Extra) != 1 { return "", fmt.Errorf("The type: %s should have 1 extra type, but has %d", rt.Name, len(rt.Extra)) } resolveName, err := rt.Extra[0].ResolveName(scope) if err != nil { return "", err } name = fmt.Sprintf("[]%s", resolveName) case KindMap: if len(rt.Extra) != 2 { return "", fmt.Errorf("The type: %s should have 2 extra type, but has %d", rt.Name, len(rt.Extra)) } resolveKey, err := rt.Extra[0].ResolveName(scope) if err != nil { return "", err } resolveValue, err := rt.Extra[1].ResolveName(scope) if err != nil { return "", err } name = fmt.Sprintf("map[%s]%s", resolveKey, resolveValue) case KindChan: if len(rt.Extra) != 1 { return "", fmt.Errorf("The type: %s should have 1 extra type, but has %d", rt.Name, len(rt.Extra)) } resolveName, err := rt.Extra[0].ResolveName(scope) if err != nil { return "", err } name = fmt.Sprintf("chan %s", resolveName) } if scope != nil && rt.Scope != &BaseModel && rt.Scope.Package != scope.Package { name = rt.Scope.PackageName + "." + name } if rt.Kind == KindStruct { name = "*" + name } return name, nil } func (rt *Type) IsBinary() bool { return rt.Category == CategoryBinary && (rt.Kind == KindSlice || rt.Kind == KindArray) } func (rt *Type) IsBaseType() bool { return rt.Kind < KindComplex64 } func (rt *Type) IsSettable() bool { switch rt.Kind { case KindArray, KindChan, KindFunc, KindInterface, KindMap, KindPtr, KindSlice, KindUnsafePointer: return true } return false } type TypeDef struct { Scope *Model Alias string Type *Type } type Constant struct { Scope *Model Name string Type *Type Value Literal } type Literal interface { Expression() string } type Variable struct { Scope *Model Name string Type *Type Value Literal } type Function struct { Scope *Model Name string Args []Variable Rets []Variable Code string } type Method struct { Scope *Model ReceiverName string ReceiverType *Type ByPtr bool Function } type Enum struct { Scope *Model Name string GoType string Values []Constant } type Struct struct { Scope *Model Name string Fields []Field Category Category LeadingComments string } type Field struct { Scope *Struct Name string Type *Type IsSetDefault bool DefaultValue Literal Required RequiredNess Tags Tags LeadingComments string TrailingComments string IsPointer bool } type Oneof struct { MessageName string OneofName string InterfaceName string Choices []Choice } type Choice struct { MessageName string ChoiceName string Type *Type } type Tags []Tag type Tag struct { Key string Value string IsDefault bool // default tag } func (ts Tags) String() string { ret := make([]string, 0, len(ts)) for _, t := range ts { ret = append(ret, fmt.Sprintf("%v:%q", t.Key, t.Value)) } return strings.Join(ret, " ") } func (ts *Tags) Remove(name string) { ret := make([]Tag, 0, len(*ts)) for _, t := range *ts { if t.Key != name { ret = append(ret, t) } } *ts = ret } func (ts Tags) Len() int { return len(ts) } func (ts Tags) Less(i, j int) bool { return ts[i].Key < ts[j].Key } func (ts Tags) Swap(i, j int) { ts[i], ts[j] = ts[j], ts[i] } func (f Field) GenGoTags() string { if len(f.Tags) == 0 { return "" } return fmt.Sprintf("`%s`", f.Tags.String()) }