func printExportFunction(ctx context.Context, env *envctx.Env, g *builder.Builder, export *sysctx.SysExportInfo) error { g.Println("func ", system.GoName(export.Name), "() *", g.SprintRef(export.TypePackage, system.GoName(export.TypeName)), " {") { g.Print("ctx := ") g.PrintFunctionCall("kego.io/system", "NewContext", g.SprintFunctionCall("context", "Background"), strconv.Quote(env.Path), fmt.Sprintf("%#v", env.Aliases), ) g.Println() g.Println("o := new(", g.SprintRef(export.TypePackage, system.GoName(export.TypeName)), ")") g.Print("err := ") g.PrintMethodCall("o", "Unpack", "ctx", g.SprintFunctionCall("kego.io/system", "MustPackString", strconv.Quote(string(export.JsonContents))), "false", ) g.Println() g.Println("if err != nil {") { g.Println("panic(err.Error())") } g.Println("}") g.Println("return o") } g.Println("}") return nil }
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 printUnpacker(ctx context.Context, env *envctx.Env, g *builder.Builder, typ *system.Type) error { name := system.GoName(typ.Id.Name) fmtPkg := g.Imports.Add("fmt") g.Println("func (v *", name, ") Unpack(ctx ", g.SprintRef("context", "Context"), ", in ", g.SprintRef("kego.io/system", "Packed"), ", iface bool) error {") { g.Println("if in == nil || in.Type() == ", g.SprintRef("kego.io/system", "J_NULL"), " {") { g.Println("return nil") } g.Println("}") kind, _ := typ.Kind(ctx) switch kind { case system.KindStruct: structType := typ if typ.Alias != nil { structType = system.WrapRule(ctx, typ.Alias).Parent } for _, embedRef := range structType.AllEmbeds() { embedType, ok := system.GetTypeFromCache(ctx, embedRef.Package, embedRef.Name) if !ok { return kerr.New("IOEEVJCDPU", "Type %s not found", embedRef.String()) } embedName := system.GoName(embedRef.Name) embedTypeName := builder.Reference(embedType.Id.Package, system.GoName(embedType.Id.Name), env.Path, g.Imports.Add) g.Println("if v.", embedName, " == nil {") { g.Println("v.", embedName, " = new(", embedTypeName, ")") } g.Println("}") g.Println("if err := v.", embedName, ".Unpack(ctx, in, false); err != nil {") { g.Println("return err") } g.Println("}") if embedRef.Package == "kego.io/system" && embedRef.Name == "object" { g.Println("if err := v.Object.InitializeType(", strconv.Quote(typ.Id.Package), ", ", strconv.Quote(typ.Id.Name), "); err != nil {") { g.Println("return err") } g.Println("}") } } for _, f := range structType.SortedFields() { g.Println("if field, ok := in.Map()[", strconv.Quote(f.Name), "]; ok && field.Type() != ", g.SprintRef("kego.io/system", "J_NULL"), " {") { in := "field" out := "ob0" depth := 0 if err := printUnpackCode(ctx, env, g, in, out, depth, f.Rule); err != nil { return kerr.Wrap("QLARKEBDBJ", err) } g.Println("v.", system.GoName(f.Name), " = ", out) } if dr, ok := f.Rule.(system.DefaultRule); ok && dr.GetDefault() != nil { g.Println("} else {") { b, err := json.Marshal(dr.GetDefault()) if err != nil { return kerr.Wrap("DLOUEHXVJF", err) } in := g.SprintFunctionCall("kego.io/system", "Pack", string(b)) out := "ob0" depth := 0 if err := printUnpackCode(ctx, env, g, in, out, depth, f.Rule); err != nil { return kerr.Wrap("UOWRFWSTNT", err) } g.Println("v.", system.GoName(f.Name), " = ", out) } g.Println("}") } else { g.Println("}") } } case system.KindValue: g.Println("if in.Type() == ", g.SprintRef("kego.io/system", "J_MAP"), " {") { g.Println("in = in.Map()[\"value\"]") } g.Println("}") switch typ.NativeJsonType(ctx) { case system.J_BOOL: g.Println("if in.Type() != ", g.SprintRef("kego.io/system", "J_BOOL"), " {") { g.Println("return ", fmtPkg, `.Errorf("Invalid type %s while unpacking a bool.", in.Type())`) } g.Println("}") g.Println("*v = ", name, "(in.Bool())") case system.J_STRING: g.Println("if in.Type() != ", g.SprintRef("kego.io/system", "J_STRING"), " {") { g.Println("return ", fmtPkg, `.Errorf("Invalid type %s while unpacking a string.", in.Type())`) } g.Println("}") g.Println("*v = ", name, "(in.String())") case system.J_NUMBER: g.Println("if in.Type() != ", g.SprintRef("kego.io/system", "J_NUMBER"), " {") { g.Println("return ", fmtPkg, `.Errorf("Invalid type %s while unpacking a number.", in.Type())`) } g.Println("}") g.Println("*v = ", name, "(in.Number())") default: panic(fmt.Sprintf("invalid type kind: %s, json native: %s", kind, typ.NativeJsonType(ctx))) } case system.KindArray: g.Println("if in.Type() == ", g.SprintRef("kego.io/system", "J_MAP"), " {") { g.Println("in = in.Map()[\"value\"]") } g.Println("}") g.Println("if in.Type() != ", g.SprintRef("kego.io/system", "J_ARRAY"), " {") { g.Println("return ", fmtPkg, `.Errorf("Invalid type %s while unpacking an array.", in.Type())`) } g.Println("}") in := "in" out := "ob0" depth := 0 if err := printUnpackCode(ctx, env, g, in, out, depth, typ.Alias); err != nil { return kerr.Wrap("VELYRXXGMC", err) } g.Println("*v = ", out) case system.KindMap: g.Println("if iface {") { g.Println("if in.Type() != ", g.SprintRef("kego.io/system", "J_MAP"), " {") { g.Println("return ", fmtPkg, `.Errorf("Invalid type %s while unpacking a map.", in.Type())`) } g.Println("}") g.Println("in = in.Map()[\"value\"]") } g.Println("}") g.Println("if in.Type() != ", g.SprintRef("kego.io/system", "J_MAP"), " {") { g.Println("return ", fmtPkg, `.Errorf("Invalid type %s while unpacking an array.", in.Type())`) } g.Println("}") in := "in" out := "ob0" depth := 0 if err := printUnpackCode(ctx, env, g, in, out, depth, typ.Alias); err != nil { return kerr.Wrap("TNEIUAFUNY", err) } g.Println("*v = ", out) } } g.Println("return nil") g.Println("}") return nil }
func printRepackCode(ctx context.Context, env *envctx.Env, g *builder.Builder, in string, out string, depth int, f system.RuleInterface, inStruct bool) error { field := system.WrapRule(ctx, f) kind, alias := field.Kind(ctx) repackerDef := g.SprintRef("kego.io/system", "Repacker") switch { case kind == system.KindInterface: valueVar := out + "_value" g.Println("var ", out, " interface{}") g.Println(valueVar, ", pkg, name, typ, err := ", in, ".(", repackerDef, ").Repack(ctx)") g.Println("if err != nil {") { g.Println(`return nil, "", "", "", err`) } g.Println("}") should := g.SprintFunctionCall( "kego.io/system", "ShouldUseExplicitTypeNotation", "pkg", "name", "typ", strconv.Quote(field.Parent.Id.Package), strconv.Quote(field.Parent.Id.Name)) g.Println("if ", should, " {") { newReferenceDef := g.SprintRef("kego.io/system", "NewReference") g.Println("typRef := ", newReferenceDef, "(pkg, name)") g.Println("typeVal, err := typRef.ValueContext(ctx)") g.Println("if err != nil {") { g.Println(`return nil, "", "", "", err`) } g.Println("}") g.Println(out, " = map[string]interface{}{") { g.Println("\"type\": typeVal,") g.Println("\"value\": ", valueVar, ",") } g.Println("}") } g.Println("} else {") { g.Println(out, " = ", valueVar) } g.Println("}") case kind == system.KindStruct || (alias && inStruct): g.Println(out, ", _, _, _, err := ", in, ".Repack(ctx)") g.Println("if err != nil {") { g.Println(`return nil, "", "", "", err`) } g.Println("}") case kind == system.KindValue: g.Println(out, " := ", in) case kind == system.KindArray: iVar := fmt.Sprintf("i%d", depth) g.Println(out, " := []interface{}{}") g.Println("for ", iVar, " := range ", in, " {") { childIn := in + "[" + iVar + "]" childDepth := depth + 1 childOut := fmt.Sprintf("ob%d", childDepth) childRule, err := field.ItemsRule() if err != nil { return kerr.Wrap("VUKWDVGVAT", err) } if err := printRepackCode(ctx, env, g, childIn, childOut, childDepth, childRule.Interface, true); err != nil { return kerr.Wrap("GDWUQWGFUI", err) } g.Println(out, " = append(", out, ", ", childOut, ")") } g.Println("}") case kind == system.KindMap: kVar := fmt.Sprintf("k%d", depth) g.Println(out, " := map[string]interface{}{}") g.Println("for ", kVar, " := range ", in, " {") { childIn := in + "[" + kVar + "]" childDepth := depth + 1 childOut := fmt.Sprintf("ob%d", childDepth) childRule, err := field.ItemsRule() if err != nil { return kerr.Wrap("NYDJVRENGA", err) } if err := printRepackCode(ctx, env, g, childIn, childOut, childDepth, childRule.Interface, true); err != nil { return kerr.Wrap("VNWOUDMDQC", err) } g.Println(out, "[", kVar, "] = ", childOut) } g.Println("}") } return nil }