From b5d927c49f05dabbd1a3782decf297467d6d5f64 Mon Sep 17 00:00:00 2001 From: Cory Slep Date: Wed, 19 Dec 2018 09:44:57 +0100 Subject: [PATCH] Properties now have serialization references to Types. This setup allows properties to recur deserializing into types as necessary, and sets the groundwork for successfully handling all kinds of JSON-LD input. --- tools/exp/convert/convert.go | 34 +++++++++++++++++++++++++- tools/exp/props/funcprop.go | 44 +++++++++++++++++----------------- tools/exp/props/nonfuncprop.go | 18 +++++++------- tools/exp/props/property.go | 9 +++---- tools/exp/props/type.go | 27 +++++++++------------ 5 files changed, 80 insertions(+), 52 deletions(-) diff --git a/tools/exp/convert/convert.go b/tools/exp/convert/convert.go index c7994cd..900f386 100644 --- a/tools/exp/convert/convert.go +++ b/tools/exp/convert/convert.go @@ -262,7 +262,12 @@ func (c Converter) convertType(t rdf.VocabularyType, if e != nil { return } - // Apply disjoint if both sides are available. + // Apply disjoint if both sides are available because the TypeGenerator + // does not know the entire vocabulary, so cannot do this lookup and + // create this connection for us. + // + // TODO: Pass in the disjoint and have the TypeGenerator complete the + // doubly-linked connection for us. for _, disj := range t.DisjointWith { if len(disj.Vocab) != 0 { // TODO: This should be fixed to handle references @@ -273,6 +278,33 @@ func (c Converter) convertType(t rdf.VocabularyType, tg.AddDisjoint(disjointType) } } + // Apply the type's KindSerializationFuncs to the property because there + // is no way for the TypeGenerator to know all properties who have a + // range of this type. + // + // TODO: Pass in these properties to the TypeGenerator constructor so it + // can build these double-links properly. Note this would also need to + // apply to referenced properties, possibly. + for _, prop := range existingFProps { + for _, kind := range prop.Kinds { + if kind.Name.LowerName == tg.TypeName() { + ser, deser, less := tg.KindSerializationFuncs() + if e = prop.SetKindFns(tg.TypeName(), ser, deser, less); e != nil { + return + } + } + } + } + for _, prop := range existingNFProps { + for _, kind := range prop.Kinds { + if kind.Name.LowerName == tg.TypeName() { + ser, deser, less := tg.KindSerializationFuncs() + if e = prop.SetKindFns(tg.TypeName(), ser, deser, less); e != nil { + return + } + } + } + } return } diff --git a/tools/exp/props/funcprop.go b/tools/exp/props/funcprop.go index 7b49bdc..860cc3e 100644 --- a/tools/exp/props/funcprop.go +++ b/tools/exp/props/funcprop.go @@ -113,7 +113,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method { } methods := []*codegen.Method{ codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), kindIndexMethod, p.StructName(), /*params=*/ nil, @@ -129,7 +129,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method { // IsLanguageMap Method methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), isLanguageMapMethod, p.StructName(), /*params=*/ nil, @@ -154,7 +154,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method { // HasLanguage Method methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), hasLanguageMethod, p.StructName(), []jen.Code{jen.Id("bcp47").String()}, @@ -182,7 +182,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method { // GetLanguage Method methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), getLanguageMethod, p.StructName(), []jen.Code{jen.Id("bcp47").String()}, @@ -214,7 +214,7 @@ func (p *FunctionalPropertyGenerator) funcs() []*codegen.Method { // SetLanguage Method methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), setLanguageMethod, p.StructName(), []jen.Code{ @@ -273,7 +273,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, [ } serialize := []*codegen.Method{ codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), p.serializeFnName(), p.StructName(), /*params=*/ nil, @@ -319,7 +319,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, [ if p.asIterator { deserialize = append(deserialize, codegen.NewCommentedFunction( - p.packageName(), + p.PackageName(), p.DeserializeFnName(), []jen.Code{jen.Id("i").Interface()}, []jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()}, @@ -335,7 +335,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, [ } else { deserialize = append(deserialize, codegen.NewCommentedFunction( - p.packageName(), + p.PackageName(), p.DeserializeFnName(), []jen.Code{jen.Id("m").Map(jen.String()).Interface()}, []jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()}, @@ -421,7 +421,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method { } if p.Kinds[0].Nilable { methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), hasMethod, p.StructName(), /*params=*/ nil, @@ -431,7 +431,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method { )) } else { methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), hasMethod, p.StructName(), /*params=*/ nil, @@ -443,7 +443,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method { // Get Method getComment := jen.Commentf("%s returns the value of this property. When %s returns false, %s will return any arbitrary value.", getMethod, hasMethod, getMethod) methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), p.getFnName(0), p.StructName(), /*params=*/ nil, @@ -465,7 +465,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method { } if p.Kinds[0].Nilable { methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), p.setFnName(0), p.StructName(), []jen.Code{jen.Id("v").Id(p.Kinds[0].ConcreteKind)}, @@ -478,7 +478,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method { )) } else { methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), p.setFnName(0), p.StructName(), []jen.Code{jen.Id("v").Id(p.Kinds[0].ConcreteKind)}, @@ -507,7 +507,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method { } if p.Kinds[0].Nilable { methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), p.clearMethodName(), p.StructName(), /*params=*/ nil, @@ -517,7 +517,7 @@ func (p *FunctionalPropertyGenerator) singleTypeFuncs() []*codegen.Method { )) } else { methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), p.clearMethodName(), p.StructName(), /*params=*/ nil, @@ -602,7 +602,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method { ) } methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), hasAnyMethodName, p.StructName(), /*params=*/ nil, @@ -626,7 +626,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method { clearLine = append(clearLine, jen.Id(codegen.This()).Dot(langMapMember).Op("=").Nil()) } methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), p.clearMethodName(), p.StructName(), /*params=*/ nil, @@ -649,7 +649,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method { } if kind.Nilable { methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), p.isMethodName(i), p.StructName(), /*params=*/ nil, @@ -659,7 +659,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method { )) } else { methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), p.isMethodName(i), p.StructName(), /*params=*/ nil, @@ -684,7 +684,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method { } if kind.Nilable { methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), p.setFnName(i), p.StructName(), []jen.Code{jen.Id("v").Id(kind.ConcreteKind)}, @@ -697,7 +697,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method { )) } else { methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), p.setFnName(i), p.StructName(), []jen.Code{jen.Id("v").Id(kind.ConcreteKind)}, @@ -715,7 +715,7 @@ func (p *FunctionalPropertyGenerator) multiTypeFuncs() []*codegen.Method { for i, kind := range p.Kinds { getComment := jen.Commentf("%s returns the value of this property. When %s returns false, %s will return an arbitrary value.", p.getFnName(i), p.isMethodName(i), p.getFnName(i)) methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), p.getFnName(i), p.StructName(), /*params=*/ nil, diff --git a/tools/exp/props/nonfuncprop.go b/tools/exp/props/nonfuncprop.go index 0f00337..9094abd 100644 --- a/tools/exp/props/nonfuncprop.go +++ b/tools/exp/props/nonfuncprop.go @@ -90,7 +90,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method { prependMethodName := fmt.Sprintf("%s%s", prependMethod, p.kindCamelName(i)) methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), prependMethodName, p.StructName(), []jen.Code{jen.Id("v").Id(kind.ConcreteKind)}, @@ -108,7 +108,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method { appendMethodName := fmt.Sprintf("%s%s", appendMethod, p.kindCamelName(i)) methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), appendMethodName, p.StructName(), []jen.Code{jen.Id("v").Id(kind.ConcreteKind)}, @@ -140,7 +140,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method { // Remove Method methods = append(methods, codegen.NewCommentedPointerMethod( - p.packageName(), + p.PackageName(), removeMethod, p.StructName(), []jen.Code{jen.Id("idx").Int()}, @@ -176,7 +176,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method { // Len Method methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), lenMethod, p.StructName(), /*params=*/ nil, @@ -192,7 +192,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method { // Swap Method methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), swapMethod, p.StructName(), []jen.Code{ @@ -213,7 +213,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method { // Less Method methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), lessMethod, p.StructName(), []jen.Code{ @@ -235,7 +235,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method { // Kind Method methods = append(methods, codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), kindIndexMethod, p.StructName(), []jen.Code{jen.Id("idx").Int()}, @@ -255,7 +255,7 @@ func (p *NonFunctionalPropertyGenerator) funcs() []*codegen.Method { func (p *NonFunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method, []*codegen.Function) { serialize := []*codegen.Method{ codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), p.serializeFnName(), p.StructName(), /*params=*/ nil, @@ -323,7 +323,7 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() ([]*codegen.Method } deserialize := []*codegen.Function{ codegen.NewCommentedFunction( - p.packageName(), + p.PackageName(), p.DeserializeFnName(), []jen.Code{jen.Id("m").Map(jen.String()).Interface()}, []jen.Code{jen.Id(p.StructName()), jen.Error()}, diff --git a/tools/exp/props/property.go b/tools/exp/props/property.go index 574ced8..3145b87 100644 --- a/tools/exp/props/property.go +++ b/tools/exp/props/property.go @@ -84,8 +84,8 @@ type PropertyGenerator struct { asIterator bool } -// packageName returns the name of the package for the property to be generated. -func (p *PropertyGenerator) packageName() string { +// PackageName returns the name of the package for the property to be generated. +func (p *PropertyGenerator) PackageName() string { return p.Package } @@ -96,7 +96,7 @@ func (p *PropertyGenerator) packageName() string { // // This feels very hacky. func (p *PropertyGenerator) SetKindFns(name string, ser, deser, less *codegen.Function) error { - for _, kind := range p.Kinds { + for i, kind := range p.Kinds { if kind.Name.LowerName == name { if kind.SerializeFn != nil || kind.DeserializeFn != nil || kind.LessFn != nil { return fmt.Errorf("property kind already has serialization functions set for %q", name) @@ -104,6 +104,7 @@ func (p *PropertyGenerator) SetKindFns(name string, ser, deser, less *codegen.Fu kind.SerializeFn = ser kind.DeserializeFn = deser kind.LessFn = less + p.Kinds[i] = kind return nil } } @@ -200,7 +201,7 @@ func (p *PropertyGenerator) clearMethodName() string { func (p *PropertyGenerator) commonMethods() []*codegen.Method { return []*codegen.Method{ codegen.NewCommentedValueMethod( - p.packageName(), + p.PackageName(), nameMethod, p.StructName(), /*params=*/ nil, diff --git a/tools/exp/props/type.go b/tools/exp/props/type.go index 6939a82..66437ec 100644 --- a/tools/exp/props/type.go +++ b/tools/exp/props/type.go @@ -37,6 +37,7 @@ func TypeInterface(pkg string) *codegen.Interface { // Property represents a property of an ActivityStreams type. type Property interface { + PackageName() string PropertyName() string StructName() string SetKindFns(name string, ser, deser, less *codegen.Function) error @@ -65,6 +66,9 @@ type TypeGenerator struct { // // All TypeGenerators must be created before the Definition method is called, to // ensure that type extension, in the inheritence sense, is properly set up. +// Additionally, all properties whose range is this type should have their +// SetKindFns method called with this TypeGenerator's KindSerializationFuncs for +// all code generation to correctly reference each other. func NewTypeGenerator(packageName, typeName, comment string, properties, withoutProperties []Property, extends, disjoint []*TypeGenerator) (*TypeGenerator, error) { @@ -93,14 +97,6 @@ func NewTypeGenerator(packageName, typeName, comment string, for _, ext := range extends { ext.extendedBy = append(ext.extendedBy, t) } - // TODO: Fix: Only notify properties whose Range is this type, not the - // properties this type has (which is wrong and currently borken) - for _, property := range t.properties { - ser, deser, less := t.kindSerializationFuncs() - if err := property.SetKindFns(t.TypeName(), ser, deser, less); err != nil { - return nil, err - } - } return t, nil } @@ -172,7 +168,7 @@ func (t *TypeGenerator) Definition() *codegen.Struct { t.cacheOnce.Do(func() { members := t.members() m := t.serializationMethod() - ser, deser, less := t.kindSerializationFuncs() + ser, deser, less := t.KindSerializationFuncs() t.cachedStruct = codegen.NewStruct( jen.Commentf(t.Comment()), t.TypeName(), @@ -387,9 +383,9 @@ func (t *TypeGenerator) serializationMethod() (ser *codegen.Method) { return } -// kindSerializationFuncs returns free function references that can be used to +// KindSerializationFuncs returns free function references that can be used to // treat a TypeGenerator as another property's Kind. -func (t *TypeGenerator) kindSerializationFuncs() (ser, deser, less *codegen.Function) { +func (t *TypeGenerator) KindSerializationFuncs() (ser, deser, less *codegen.Function) { serName := fmt.Sprintf("%s%s", serializeMethodName, t.TypeName()) ser = codegen.NewCommentedFunction( t.packageName, @@ -404,20 +400,19 @@ func (t *TypeGenerator) kindSerializationFuncs() (ser, deser, less *codegen.Func jen.Commentf("%s calls %s on the %s type.", serName, serializeMethodName, t.TypeName())) deserName := fmt.Sprintf("%s%s", deserializeFnName, t.TypeName()) deserCode := jen.Empty() - for name := range t.allProperties() { + for name, prop := range t.allProperties() { deserCode = deserCode.Add( jen.If( jen.List( jen.Id("p"), jen.Err(), - // TODO: Qual - ).Op(":=").Qual("", deserializeFnName).Call(jen.Id("m")), + ).Op(":=").Qual(prop.PackageName(), deserializeMethod).Call(jen.Id("m")), jen.Err().Op("!=").Nil(), ).Block( jen.Return(jen.Nil(), jen.Err()), ).Else().Block( - jen.Id(codegen.This()).Dot(strings.Title(name)).Op(":=").Op("*").Id("p"), - )) + jen.Id(codegen.This()).Dot(strings.Title(name)).Op("=").Op("*").Id("p"), + ).Line()) } deser = codegen.NewCommentedFunction( t.packageName,