// TypeDefinition returns the Go source for the definition of the type // [optional pointer][collection prefix][optional pointer][type name] func TypeDefinition(ctx context.Context, field system.RuleInterface, path string, getAlias func(string) string) (string, error) { outer := system.WrapRule(ctx, field) outerPointer := outer.PassedAsPointerString(ctx) // if the rule is a complex collection, with possibly several maps and // arrays, this iterates over the rule and returns the go collection prefix // - e.g. []map[string] for an array of maps. It also returns the inner rule. prefix, inner, err := collectionPrefixInnerRule(ctx, "", outer) if err != nil { return "", kerr.Wrap("SOGEFOPJHB", err) } innerPointer := "" // if we have a prefix we should also work out the innerPointer if prefix != "" && inner.PassedAsPointer(ctx) { innerPointer = "*" } var n string if inner.Struct.Interface { n = system.GoInterfaceName(inner.Parent.Id.Name) } else { n = system.GoName(inner.Parent.Id.Name) } name := Reference(inner.Parent.Id.Package, n, path, getAlias) return fmt.Sprint(outerPointer, prefix, innerPointer, name), nil }
func printInterfaceDefinition(ctx context.Context, env *envctx.Env, g *builder.Builder, typ *system.Type) { g.Println("type ", system.GoInterfaceName(typ.Id.Name), " interface {") { g.Println("Get", system.GoName(typ.Id.Name), "(ctx ", builder.Reference("context", "Context", env.Path, g.Imports.Add), ") ", typ.PassedAsPointerString(ctx), system.GoName(typ.Id.Name)) } g.Println("}") }
func printInitFunction(ctx context.Context, env *envctx.Env, g *builder.Builder, types *sysctx.SysTypes) { g.Println("func init() {") { g.Print("pkg := ") g.PrintFunctionCall( "kego.io/context/jsonctx", "InitPackage", strconv.Quote(env.Path), ) g.Println("") g.PrintMethodCall("pkg", "SetHash", env.Hash) g.Println("") for _, name := range types.Keys() { t, ok := types.Get(name) if !ok { // ke: {"block": {"notest": true}} continue } typ := t.Type.(*system.Type) isRule := typ.Id.IsRule() if isRule { continue } interfaceFunc := "nil" isNativeCollection := typ.IsNativeCollection() && typ.Alias == nil if !isNativeCollection { var ifaceName string if typ.Interface { ifaceName = system.GoName(typ.Id.Name) } else { ifaceName = system.GoInterfaceName(typ.Id.Name) } reflectTypeof := g.SprintFunctionCall( "reflect", "TypeOf", fmt.Sprintf("(*%s)(nil)", ifaceName), ) + ".Elem()" reflectType := builder.Reference("reflect", "Type", env.Path, g.Imports.Add) interfaceFunc = "func() " + reflectType + " { return " + reflectTypeof + " }" } newFunc := "nil" derefFunc := "nil" if typ.Interface { newFunc = "func() interface{} { return (*" + system.GoName(typ.Id.Name) + ")(nil) }" } else if !typ.IsNativeCollection() || typ.Alias != nil { newFunc = "func() interface{} { return new(" + system.GoName(typ.Id.Name) + ")}" if !typ.PassedAsPointer(ctx) { derefFunc = "func(in interface{}) interface{} {return *in.(*" + system.GoName(typ.Id.Name) + ")}" } } g.Println("pkg.Init(") { g.Println(strconv.Quote(typ.Id.Name), ",") g.Println(newFunc, ",") g.Println(derefFunc, ",") g.Println("func() interface{} { return new("+system.GoName(typ.Id.ChangeToRule().Name)+")}", ",") g.Println(interfaceFunc, ",") } g.Println(")") g.Println("") } } g.Println("}") }
func printInterfaceUnpacker(ctx context.Context, env *envctx.Env, g *builder.Builder, typ *system.Type) { // if type kind is native, also accept bare json native // if type kind is array, also accept bare json array typeName := system.GoName(typ.Id.Name) var interfaceName string if typ.Interface { interfaceName = system.GoName(typ.Id.Name) } else { interfaceName = system.GoInterfaceName(typ.Id.Name) } fmtPkg := g.Imports.Add("fmt") g.Println("func Unpack", interfaceName, "(ctx ", g.SprintRef("context", "Context"), ", in ", g.SprintRef("kego.io/system", "Packed"), ") (", interfaceName, ", error) {") { g.Println("switch in.Type() {") { g.Println("case ", g.SprintRef("kego.io/system", "J_MAP"), ":") { unknownTypeFunc := g.SprintFunctionCall("kego.io/system", "UnpackUnknownType", "ctx", "in", "true", strconv.Quote(typ.Id.Package), strconv.Quote(typ.Id.Name)) g.Println("i, err := ", unknownTypeFunc) g.Println("if err != nil {") { g.Println("return nil, err") } g.Println("}") g.Println("ob, ok := i.(", interfaceName, ")") g.Println("if !ok {") { g.Println("return nil, ", fmtPkg, `.Errorf("%T does not implement `, interfaceName, `", i)`) } g.Println("}") g.Println("return ob, nil") } switch typ.NativeJsonType(ctx) { // We don't include J_MAP in here. case system.J_STRING, system.J_NUMBER, system.J_BOOL, system.J_ARRAY: switch typ.NativeJsonType(ctx) { case system.J_STRING: g.Println("case ", g.SprintRef("kego.io/system", "J_STRING"), ":") case system.J_NUMBER: g.Println("case ", g.SprintRef("kego.io/system", "J_NUMBER"), ":") case system.J_BOOL: g.Println("case ", g.SprintRef("kego.io/system", "J_BOOL"), ":") case system.J_ARRAY: g.Println("case ", g.SprintRef("kego.io/system", "J_ARRAY"), ":") } g.Println("ob := new(", typeName, ")") g.Println("if err := ob.Unpack(ctx, in, false); err != nil {") { g.Println("return nil, err") } g.Println("}") g.Println("return ob, nil") } g.Println("default:") { g.Println("return nil, ", fmtPkg, `.Errorf("Unsupported json type %s when unpacking into `, interfaceName, `.", in.Type())`) } } g.Println("}") } g.Println("}") }
func printUnpackCode(ctx context.Context, env *envctx.Env, g *builder.Builder, in string, out string, depth int, f system.RuleInterface) error { field := system.WrapRule(ctx, f) fieldType := field.Parent fieldTypeName := builder.Reference(fieldType.Id.Package, system.GoName(fieldType.Id.Name), env.Path, g.Imports.Add) kind, alias := field.Kind(ctx) switch { case kind == system.KindStruct || alias: ptr := fieldType.PassedAsPointerInverseString(ctx) g.Println(out, " := ", ptr, "new(", fieldTypeName, ")") g.Println("if err := ", out, ".Unpack(ctx, ", in, ", false); err != nil {") { g.Println("return err") } g.Println("}") //if store { // g.Println("v.", fieldName, " = ob") //} case kind == system.KindValue: var funcName string switch fieldType.NativeJsonType(ctx) { case system.J_STRING: funcName = "UnpackString" case system.J_NUMBER: funcName = "UnpackNumber" case system.J_BOOL: funcName = "UnpackBool" default: return kerr.New("LSGUACQGHB", "Kind == KindValue but native json type==%s", fieldType.NativeJsonType(ctx)) } funcRef := g.SprintRef("kego.io/system", funcName) g.Println(out, ", err := ", funcRef, "(ctx, ", in, ")") g.Println("if err != nil {") { g.Println("return err") } g.Println("}") //if store { // g.Println("v.", fieldName, " = ob") //} case kind == system.KindInterface: var interfaceName string if fieldType.Interface { interfaceName = system.GoName(fieldType.Id.Name) } else { interfaceName = system.GoInterfaceName(fieldType.Id.Name) } unpackFuncName := builder.Reference(fieldType.Id.Package, "Unpack"+interfaceName, env.Path, g.Imports.Add) g.Println(out, ", err := ", unpackFuncName, "(ctx, ", in, ")") g.Println("if err != nil {") { g.Println("return err") } g.Println("}") //if store { // g.Println("v.", fieldName, " = ob") //} case kind == system.KindArray: fmtPkg := g.Imports.Add("fmt") g.Println("if ", in, ".Type() != ", g.SprintRef("kego.io/system", "J_ARRAY"), " {") { g.Println("return ", fmtPkg, ".Errorf(\"Unsupported json type %s found while unpacking into an array.\", ", in, ".Type())") } g.Println("}") fieldType, err := builder.TypeDefinition(ctx, f, env.Path, g.Imports.Add) if err != nil { return kerr.Wrap("UDPMSSFLTW", err) } g.Println(out, " := ", fieldType, "{}") iVar := fmt.Sprintf("i%d", depth) g.Println("for ", iVar, " := range ", in, ".Array() {") { childRule, err := field.ItemsRule() if err != nil { return kerr.Wrap("PJQBRUEHLD", err) } childDepth := depth + 1 childIn := in + ".Array()[" + iVar + "]" childOut := fmt.Sprintf("ob%d", childDepth) if err := printUnpackCode(ctx, env, g, childIn, childOut, childDepth, childRule.Interface); err != nil { return kerr.Wrap("XCHEJPDJDS", err) } g.Println(out, " = append(", out, ", ", childOut, ")") } g.Println("}") case kind == system.KindMap: fmtPkg := g.Imports.Add("fmt") g.Println("if ", in, ".Type() != ", g.SprintRef("kego.io/system", "J_MAP"), " {") { g.Println("return ", fmtPkg, ".Errorf(\"Unsupported json type %s found while unpacking into a map.\", ", in, ".Type())") } g.Println("}") fieldType, err := builder.TypeDefinition(ctx, f, env.Path, g.Imports.Add) if err != nil { return kerr.Wrap("IHNYODUIKG", err) } g.Println(out, " := ", fieldType, "{}") kVar := fmt.Sprintf("k%d", depth) g.Println("for ", kVar, " := range ", in, ".Map() {") { items, err := field.ItemsRule() if err != nil { return kerr.Wrap("FPOBYGVOPP", err) } childDepth := depth + 1 childIn := in + ".Map()[" + kVar + "]" childOut := fmt.Sprintf("ob%d", childDepth) if err := printUnpackCode(ctx, env, g, childIn, childOut, childDepth, items.Interface); err != nil { return kerr.Wrap("ONUJJGIKJE", err) } g.Println(out, "[", kVar, "] = ", childOut) } g.Println("}") } return nil }