Add IRI support and fix all build errors.

Generated code now will also compile, for the first time in forever!
This commit is contained in:
Cory Slep 2019-01-06 22:15:07 +01:00
parent ea8af5c968
commit 7ac133d101
4 changed files with 152 additions and 36 deletions

View file

@ -7,6 +7,10 @@ import (
"sync"
)
const (
iriMember = "iri"
)
// FunctionalPropertyGenerator produces Go code for properties that can have
// only one value. The resulting property is a struct type that can have one
// value that could be from multiple Kinds of values. If there is only one
@ -306,22 +310,32 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co
jen.Nil(),
)},
jen.Commentf("%s converts this into an interface representation suitable for marshalling into a text or binary format.", p.serializeFnName()))
deserializeFns := jen.Empty()
valueDeserializeFns := jen.Empty()
typeDeserializeFns := jen.Empty()
foundValue := false
foundType := false
for i, kind := range p.Kinds {
if i > 0 {
deserializeFns = deserializeFns.Else()
}
values := jen.Dict{
jen.Id(p.memberName(i)): jen.Id("v"),
}
if !kind.Nilable {
values[jen.Id(p.hasMemberName(i))] = jen.True()
}
deserializeFns = deserializeFns.If(
tmp := jen.Empty()
if kind.isValue() && foundValue {
tmp = tmp.Else()
} else if !kind.isValue() && foundType {
tmp = tmp.Else()
}
variable := jen.Id("i")
if !kind.isValue() {
variable = jen.Id("m")
}
tmp = tmp.If(
jen.List(
jen.Id("v"),
jen.Err(),
).Op(":=").Add(kind.deserializeFnCode(jen.Id("i"))),
).Op(":=").Add(kind.deserializeFnCode(variable)),
jen.Err().Op("!=").Nil(),
).Block(
jen.Id(codegen.This()).Op(":=").Op("&").Id(p.StructName()).Values(
@ -332,9 +346,15 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co
jen.Nil(),
),
)
if kind.isValue() {
foundValue = true
valueDeserializeFns = valueDeserializeFns.Add(tmp)
} else {
foundType = true
typeDeserializeFns = typeDeserializeFns.Add(tmp)
}
}
var deserialize *codegen.Function
// TODO: IRI Value
if p.asIterator {
deserialize = codegen.NewCommentedFunction(
p.GetPrivatePackage().Path(),
@ -342,19 +362,13 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co
[]jen.Code{jen.Id("i").Interface()},
[]jen.Code{jen.Op("*").Id(p.StructName()), jen.Error()},
[]jen.Code{
p.addUnknownDeserializeCode(deserializeFns).Else().Block(
jen.Return(
jen.Nil(),
jen.Qual("fmt", "Errorf").Call(
jen.Lit("could not deserialize %q property"),
jen.Lit(p.PropertyName()),
),
p.wrapDeserializeCode(valueDeserializeFns, typeDeserializeFns, false).Line().Return(
jen.Nil(),
jen.Qual("fmt", "Errorf").Call(
jen.Lit("could not deserialize %q property"),
jen.Lit(p.PropertyName()),
),
),
jen.Return(
jen.Nil(),
jen.Nil(),
),
},
jen.Commentf("%s creates an iterator from an element that has been unmarshalled from a text or binary format.", p.DeserializeFnName()))
} else {
@ -373,7 +387,7 @@ func (p *FunctionalPropertyGenerator) serializationFuncs() (*codegen.Method, *co
),
jen.Id("ok"),
).Block(
p.addUnknownDeserializeCode(deserializeFns),
p.wrapDeserializeCode(valueDeserializeFns, typeDeserializeFns, true),
),
jen.Return(
jen.Nil(),
@ -409,6 +423,7 @@ func (p *FunctionalPropertyGenerator) singleTypeDef() *codegen.Struct {
}
}
kindMembers = append(kindMembers, p.unknownMemberDef())
kindMembers = append(kindMembers, p.iriMemberDef())
if p.HasNaturalLanguageMap {
kindMembers = append(kindMembers, jen.Id(langMapMember).Map(jen.String()).String())
}
@ -596,6 +611,7 @@ func (p *FunctionalPropertyGenerator) multiTypeDef() *codegen.Struct {
}
}
kindMembers = append(kindMembers, p.unknownMemberDef())
kindMembers = append(kindMembers, p.iriMemberDef())
if p.HasNaturalLanguageMap {
kindMembers = append(kindMembers, jen.Id(langMapMember).Map(jen.String()).String())
}
@ -820,13 +836,58 @@ func (p *FunctionalPropertyGenerator) unknownMemberDef() jen.Code {
return jen.Id(unknownMemberName).Index().Byte()
}
// addUnknownDeserializeCode generates the "else if it's a []byte" code used for
// deserializing unknown values.
func (p *FunctionalPropertyGenerator) addUnknownDeserializeCode(existing jen.Code) *jen.Statement {
if len(p.Kinds) > 0 {
existing = jen.Add(existing, jen.Else())
// iriMemberDef returns the definition of a struct member that handles
// a property whose type is an IRI.
func (p *FunctionalPropertyGenerator) iriMemberDef() jen.Code {
return jen.Id(iriMember).Op("*").Qual("net/url", "URL")
}
// wrapDeserializeCode generates the "else if it's a []byte" code and IRI code
// used for deserializing unknown values.
func (p *FunctionalPropertyGenerator) wrapDeserializeCode(valueExisting, typeExisting jen.Code, errorAtEnd bool) *jen.Statement {
iriCode := jen.Empty()
if !p.hasURIKind() {
iriCode = jen.If(
jen.List(
jen.Id("s"),
jen.Id("ok"),
).Op(":=").Id("i").Assert(jen.String()),
jen.Id("ok"),
).Block(
// IRI
jen.List(
jen.Id("u"),
jen.Err(),
).Op(":=").Qual("net/url", "Parse").Call(jen.Id("s")),
jen.Commentf("If error exists, don't error out -- skip this and treat as unknown string ([]byte) at worst"),
jen.If(jen.Err().Op("==").Nil()).Block(
jen.Id(codegen.This()).Op(":=").Op("&").Id(p.StructName()).Values(
jen.Dict{
jen.Id(iriMember): jen.Id("u"),
},
),
jen.Return(
jen.Id(codegen.This()),
jen.Nil(),
),
),
).Line()
}
return jen.Add(existing,
if p.hasTypeKind() {
iriCode = iriCode.If(
jen.List(
jen.Id("m"),
jen.Id("ok"),
).Op(":=").Id("i").Assert(jen.Map(jen.String()).Interface()),
jen.Id("ok"),
).Block(
typeExisting,
).Else()
}
if p.hasValueKind() {
iriCode = iriCode.Add(valueExisting).Else()
}
iriCode = iriCode.Add(
jen.If(
jen.List(
jen.Id("v"),
@ -847,4 +908,46 @@ func (p *FunctionalPropertyGenerator) addUnknownDeserializeCode(existing jen.Cod
),
),
)
if errorAtEnd {
iriCode = iriCode.Else().Block(
jen.Return(
jen.Nil(),
jen.Qual("fmt", "Errorf").Call(
jen.Lit("could not deserialize %q property"),
jen.Lit(p.PropertyName()),
),
),
)
}
return iriCode
}
// hasURIKind returns true if this property already has a Kind that is a URI.
func (p *FunctionalPropertyGenerator) hasURIKind() bool {
for _, k := range p.Kinds {
if k.IsURI {
return true
}
}
return false
}
// hasTypeKind returns true if this property has a Kind that is a type.
func (p *FunctionalPropertyGenerator) hasTypeKind() bool {
for _, k := range p.Kinds {
if !k.isValue() {
return true
}
}
return false
}
// hasValueKind returns true if this property has a Kind that is a Value.
func (p *FunctionalPropertyGenerator) hasValueKind() bool {
for _, k := range p.Kinds {
if k.isValue() {
return true
}
}
return false
}

View file

@ -386,8 +386,9 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() (*codegen.Method,
),
jen.Err().Op("!=").Nil(),
).Block(
jen.Id("ret").Op(":=").Id(p.StructName()).Call(jen.Id(codegen.This())),
jen.Return(
jen.Id(codegen.This()),
jen.Op("&").Id("ret"),
jen.Err(),
),
).Else().If(
@ -403,7 +404,7 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() (*codegen.Method,
p.GetPrivatePackage().Path(),
p.DeserializeFnName(),
[]jen.Code{jen.Id("m").Map(jen.String()).Interface()},
[]jen.Code{jen.Id(p.StructName()), jen.Error()},
[]jen.Code{jen.Qual(p.GetPublicPackage().Path(), p.InterfaceName()), jen.Error()},
[]jen.Code{
jen.Var().Id(codegen.This()).Index().Op("*").Id(p.iteratorTypeName().CamelName),
jen.If(
@ -436,8 +437,9 @@ func (p *NonFunctionalPropertyGenerator) serializationFuncs() (*codegen.Method,
deserializeFn("i"),
),
),
jen.Id("ret").Op(":=").Id(p.StructName()).Call(jen.Id(codegen.This())),
jen.Return(
jen.Id(codegen.This()),
jen.Op("&").Id("ret"),
jen.Nil(),
),
},

View file

@ -87,7 +87,7 @@ type Kind struct {
func (k Kind) lessFnCode(this, other *jen.Statement) *jen.Statement {
// LessFn is nil case -- call comparison Less method directly on the LHS
lessCall := this.Clone().Dot(compareLessMethod).Call(other.Clone())
if k.LessFn != nil {
if k.isValue() {
// LessFn is indeed a function -- call this function
lessCall = k.LessFn.Clone().Call(
this.Clone(),
@ -98,8 +98,7 @@ func (k Kind) lessFnCode(this, other *jen.Statement) *jen.Statement {
}
func (k Kind) deserializeFnCode(this *jen.Statement) *jen.Statement {
// LessFn is not nil, this means it is a value.
if k.LessFn != nil {
if k.isValue() {
return k.DeserializeFn.Clone().Call(this)
} else {
// If LessFn is nil, this means it is a type. Which requires an
@ -108,6 +107,13 @@ func (k Kind) deserializeFnCode(this *jen.Statement) *jen.Statement {
}
}
func (k Kind) isValue() bool {
// LessFn is not nil, this means it is a value.
// If LessFn is nil, this means it is a type. Types will have their
// LessThan method called directly on the type.
return k.LessFn != nil
}
// PropertyGenerator is a common base struct used in both Functional and
// NonFunctional ActivityStreams properties. It provides common naming patterns,
// logic, and common Go code to be generated.

View file

@ -21,6 +21,7 @@ const (
compareLessMethod = "LessThan"
getUnknownMethod = "GetUnknownProperties"
unknownMember = "unknown"
getMethodFormat = "Get%s"
)
// TypeInterface returns the Type Interface that is needed for ActivityStream
@ -559,12 +560,16 @@ func (t *TypeGenerator) lessMethod() (less *codegen.Method) {
jen.Commentf("Compare property %q", prop.PropertyName()).Line(),
jen.If(
jen.Id(codegen.This()).Dot(t.memberName(prop)).Dot(compareLessMethod).Call(
jen.Id("o").Dot(t.memberName(prop)),
jen.Id("o").Dot(
fmt.Sprintf(getMethodFormat, t.memberName(prop)),
).Call(),
),
).Block(
jen.Return(jen.True()),
).Else().If(
jen.Id("o").Dot(t.memberName(prop)).Dot(compareLessMethod).Call(
jen.Id("o").Dot(
fmt.Sprintf(getMethodFormat, t.memberName(prop)),
).Call().Dot(compareLessMethod).Call(
jen.Id(codegen.This()).Dot(t.memberName(prop)),
),
).Block(
@ -693,7 +698,7 @@ func (t *TypeGenerator) allGetters() (m []*codegen.Method) {
for _, property := range t.allProperties() {
m = append(m, codegen.NewCommentedValueMethod(
t.PrivatePackage().Path(),
fmt.Sprintf("Get%s", t.memberName(property)),
fmt.Sprintf(getMethodFormat, t.memberName(property)),
t.TypeName(),
/*params=*/ nil,
[]jen.Code{jen.Qual(property.GetPublicPackage().Path(), property.InterfaceName())},
@ -702,7 +707,7 @@ func (t *TypeGenerator) allGetters() (m []*codegen.Method) {
jen.Id(codegen.This()).Dot(t.memberName(property)),
),
},
jen.Commentf("Get%s returns the %q property if it exists, and nil otherwise.", t.memberName(property), property.PropertyName())))
jen.Commentf(getMethodFormat+" returns the %q property if it exists, and nil otherwise.", t.memberName(property), property.PropertyName())))
}
return
}
@ -719,7 +724,7 @@ func (t *TypeGenerator) allSetters() (m []*codegen.Method) {
[]jen.Code{
jen.Id(codegen.This()).Dot(t.memberName(property)).Op("=").Id("i"),
},
jen.Commentf("Get%s returns the %q property if it exists, and nil otherwise.", t.memberName(property), property.PropertyName())))
jen.Commentf("Set%s returns the %q property if it exists, and nil otherwise.", t.memberName(property), property.PropertyName())))
}
return
}